// CodeContracts
// 
// Copyright (c) Microsoft Corporation
// 
// All rights reserved. 
// 
// MIT License
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections;
#if FxCop
using System.Collections.Generic;
using AssemblyReferenceList = Microsoft.Cci.AssemblyReferenceCollection;
using AttributeList = Microsoft.Cci.AttributeNodeCollection;
using BlockList = Microsoft.Cci.BlockCollection;
using ExpressionList = Microsoft.Cci.ExpressionCollection;
using InstructionList = Microsoft.Cci.InstructionCollection;
using Int32List = System.Collections.Generic.List<int>;
using InterfaceList = Microsoft.Cci.InterfaceCollection;
using LocalList = Microsoft.Cci.LocalCollection;
using MemberList = Microsoft.Cci.MemberCollection;
using MethodList = Microsoft.Cci.MethodCollection;
using ModuleReferenceList = Microsoft.Cci.ModuleReferenceCollection;
using NamespaceList = Microsoft.Cci.NamespaceCollection;
using ParameterList = Microsoft.Cci.ParameterCollection;
using ResourceList = Microsoft.Cci.ResourceCollection;
using SecurityAttributeList = Microsoft.Cci.SecurityAttributeCollection;
using StatementList = Microsoft.Cci.StatementCollection;
using TypeNodeList = Microsoft.Cci.TypeNodeCollection;
using Win32ResourceList = Microsoft.Cci.Win32ResourceCollection;
using Property = Microsoft.Cci.PropertyNode;
using Module = Microsoft.Cci.ModuleNode;
using Class = Microsoft.Cci.ClassNode;
using Interface = Microsoft.Cci.InterfaceNode;
using Event = Microsoft.Cci.EventNode;
using Return = Microsoft.Cci.ReturnNode;
using Throw = Microsoft.Cci.ThrowNode;
using SerializedTypeNameList = System.Collections.Generic.List<SerializedTypeName>;
#if NoWriter
using StringList = System.Collections.Generic.List<string>;
#endif
#endif
#if UseSingularityPDB
using Microsoft.Singularity.PdbInfo;
using Microsoft.Singularity.PdbInfo.Features;
#endif
#if CCINamespace
using Microsoft.Cci;
#else
using System.Compiler;
#endif
using System.Diagnostics;
using System.Globalization;
using Marshal = System.Runtime.InteropServices.Marshal;
using System.Runtime.InteropServices;
using System.IO;

#if CCINamespace
namespace Microsoft.Cci.Metadata{
#else
namespace System.Compiler.Metadata{
#endif

#if !ROTOR && !UseSingularityPDB
  enum CorOpenFlags : uint{
    ofRead      =   0x00000000,     // Open scope for read
    ofWrite     =   0x00000001,     // Open scope for write.
    ofCopyMemory =  0x00000002,     // Open scope with memory. Ask metadata to maintain its own copy of memory.
    ofCacheImage =  0x00000004,     // EE maps but does not do relocations or verify image
    ofNoTypeLib =   0x00000080,     // Don't OpenScope on a typelib.
  }
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("809c652e-7396-11d2-9771-00A0C9B4D50C")]
  interface IMetaDataDispenser{
    void DefineScope (ref Guid clsid, uint createFlags, [In] ref Guid iid, [MarshalAs(UnmanagedType.IUnknown)] out object retval);    
    [PreserveSig]
    int OpenScope (string scope, uint openFlags, [In] ref Guid iid, [MarshalAs(UnmanagedType.IUnknown)] out object import);
    void OpenScopeOnMemory (IntPtr data, uint dataSize, uint openFlags, [In] ref Guid iid, [MarshalAs(UnmanagedType.IUnknown)] out object retval);
  }
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("AA544D42-28CB-11d3-BD22-0000F80849BD")]
  interface ISymUnmanagedBinder{
    [PreserveSig]
    int GetReaderForFile([MarshalAs(UnmanagedType.IUnknown)] object importer, string filename, string searchPath, out ISymUnmanagedReader reader);
    ISymUnmanagedReader GetReaderForStream([MarshalAs(UnmanagedType.IUnknown)] object importer, [MarshalAs(UnmanagedType.IUnknown)] object stream);
  }
  [ComImport, Guid("ACCEE350-89AF-4ccb-8B40-1C2C4C6F9434"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComVisible(false)]
  interface ISymUnmanagedBinder2: ISymUnmanagedBinder{
    void GetReaderForFile(IntPtr importer, [MarshalAs(UnmanagedType.LPWStr)] String filename, [MarshalAs(UnmanagedType.LPWStr)] String SearchPath, [MarshalAs(UnmanagedType.Interface)] out ISymUnmanagedReader retVal);
    void GetReaderFromStream(IntPtr importer, IntPtr stream, [MarshalAs(UnmanagedType.Interface)] out ISymUnmanagedReader retVal);
    [PreserveSig]
    int GetReaderForFile2([MarshalAs(UnmanagedType.IUnknown)] object importer, [MarshalAs(UnmanagedType.LPWStr)] String fileName, [MarshalAs(UnmanagedType.LPWStr)] String searchPath, int searchPolicy, [MarshalAs(UnmanagedType.Interface)] out ISymUnmanagedReader pRetVal);
//    void GetReaderForFile3(IntPtr importer, [MarshalAs(UnmanagedType.LPWStr)] String fileName, [MarshalAs(UnmanagedType.LPWStr)] String searchPath, int searchPolicy, IntPtr callback, [MarshalAs(UnmanagedType.Interface)] out ISymUnmanagedReader pRetVal);
  }
  [ComImport, Guid("AA544D41-28CB-11d3-BD22-0000F80849BD")]
  class CorSymBinder{ 
  }
  [ComImport, Guid("0A29FF9E-7F9C-4437-8B11-F424491E3931")]
  class CorSymBinder2{
  }
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("B4CE6286-2A6B-3712-A3B7-1EE1DAD467B5")]
  interface ISymUnmanagedReader{
    ISymUnmanagedDocument GetDocument(string url, ref Guid language, ref Guid languageVendor, ref Guid documentType);
    void GetDocuments(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] ISymUnmanagedDocument[] docs);
    uint GetUserEntryPoint();
    [PreserveSig]
    int GetMethod(uint token, ref ISymUnmanagedMethod method);
    ISymUnmanagedMethod GetMethodByVersion(uint token, int version);
    void GetVariables(uint parent, uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] ISymUnmanagedVariable[] vars);
    void GetGlobalVariables(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] ISymUnmanagedVariable[] vars);
    ISymUnmanagedMethod GetMethodFromDocumentPosition(ISymUnmanagedDocument document, uint line, uint column);
    void GetSymAttribute(uint parent, string name, ulong size, ref uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)] byte[] buffer);
    void GetNamespaces(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] IntPtr[] namespaces);
    void Initialize([MarshalAs(UnmanagedType.IUnknown)] object importer, string filename, string searchPath, [MarshalAs(UnmanagedType.IUnknown)] object stream);
    void UpdateSymbolStore(string filename, [MarshalAs(UnmanagedType.IUnknown)] object stream);
    void ReplaceSymbolStore(string filename, [MarshalAs(UnmanagedType.IUnknown)] object stream);
    void GetSymbolStoreFileName(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] char[] name);
    void GetMethodsFromDocumentPosition(ISymUnmanagedDocument document, uint line, uint column, uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=3)] ISymUnmanagedMethod[] retval);
    void GetDocumentVersion(ISymUnmanagedDocument doc, out int version, out bool isLatest);
    void GetMethodVersion(ISymUnmanagedMethod method, out int version);
  }
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("B62B923C-B500-3158-A543-24F307A8B7E1")]
  interface ISymUnmanagedMethod{
    uint GetToken();
    uint GetSequencePointCount();
    ISymUnmanagedScope GetRootScope();
    ISymUnmanagedScope GetScopeFromOffset(uint offset);
    uint Getoffset(ISymUnmanagedDocument document, uint line, uint column);
    void GetRanges(ISymUnmanagedDocument document, uint line, uint column, uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=3)] uint[] ranges);
    void GetParameters(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] ISymUnmanagedVariable[] parms);
    IntPtr GetNamespace();
    bool GetSourceStartEnd([MarshalAs(UnmanagedType.LPArray,SizeConst=2)] ISymUnmanagedDocument[] docs, [MarshalAs(UnmanagedType.LPArray)] uint[] lines, [MarshalAs(UnmanagedType.LPArray)] uint[] columns);
    void GetSequencePoints(uint size, out uint length, 
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] uint[] offsets,
      [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.IUnknown, SizeParamIndex=0)] IntPtr[] documents,
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] uint[] lines,
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] uint[] columns,
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] uint[] endLines,
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] uint[] endColumns);
  }
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("40DE4037-7C81-3E1E-B022-AE1ABFF2CA08")]
  interface ISymUnmanagedDocument{
    void GetURL(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] char[] url);
    void GetDocumentType(out Guid retval);
    void GetLanguage(out Guid retval);
    void GetLanguageVendor(out Guid retval);
    void GetCheckSumAlgorithmId(out Guid retval);
    void GetCheckSum(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] byte[] data);
    uint FindClosestLine(uint line);
    bool HasEmbeddedSource();
    uint GetSourceLength();
    void GetSourceRange(uint startLine, uint startColumn, uint endLine, uint endColumn, uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=4)] byte[] source);
  }
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("9F60EEBE-2D9A-3F7C-BF58-80BC991C60BB")]
  interface ISymUnmanagedVariable{
    void GetName(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] char[] name);
    uint GetAttributes();
    void GetSignature(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] byte[] name);
    uint GetAddressKind();
    uint GetAddressField1();
    uint GetAddressField2();
    uint GetAddressField3();
    uint GetStartOffset();
    uint GetEndOffset();
  }
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("68005D0F-B8E0-3B01-84D5-A11A94154942")]
  interface ISymUnmanagedScope{
    ISymUnmanagedMethod GetMethod();
    ISymUnmanagedScope GetParent();
    void GetChildren (uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] IntPtr[] children);
    uint GetStartOffset();
    uint GetEndOffset();
    uint GetLocalCount();
    void GetLocals(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] IntPtr[] locals);
    void GetNamespaces(uint size, out uint length, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] IntPtr[] namespaces);
  }
#endif
  internal sealed class UnmanagedBuffer : IDisposable{
    internal IntPtr Pointer;
    internal UnmanagedBuffer(int length){
      this.Pointer = Marshal.AllocHGlobal(length);
    }
    public void Dispose(){
      if (this.Pointer != IntPtr.Zero)
        Marshal.FreeHGlobal(this.Pointer);
      this.Pointer = IntPtr.Zero;
      GC.SuppressFinalize(this);
    }
    ~UnmanagedBuffer(){
      this.Dispose();
    }
  } 
  internal unsafe class Reader : IDisposable{
    private string directory;
    private string fileName;
    private bool doNotLockFile;
    private Module/*!*/ module = new Module();
    internal TypeNode currentType;
    private long sortedTablesMask;
    internal MetadataReader/*!*/ tables;
    private UnmanagedBuffer unmanagedBuffer;
    private int bufferLength;
    private IDictionary/*!*/ localAssemblyCache; //use for simple names
    internal readonly static IDictionary/*!*/ StaticAssemblyCache = new SynchronizedWeakDictionary(); //use for strong names
    private bool useStaticCache;
    //^ [Microsoft.Contracts.SpecInternal]
    private TrivialHashtable namespaceTable;
    internal NamespaceList namespaceList;
#if CodeContracts
    internal PdbInfo pdbInfo;
#endif
#if UseSingularityPDB
    internal PdbFunction[] pdbFunctions;
#elif !ROTOR
    internal ISymUnmanagedReader debugReader;
    private System.Collections.Generic.Dictionary<IntPtr,UnmanagedDocument> debugDocuments;
#endif
#if FxCop
    internal static bool probeGAC = true;
#endif
    internal bool getDebugSymbols;
    private bool getDebugSymbolsFailed;
    private TypeNodeList currentTypeParameters;
    private TypeNodeList currentMethodTypeParameters;
    internal bool preserveShortBranches;
#if !MinimalReader
    internal unsafe Reader(byte[]/*!*/ buffer, IDictionary localAssemblyCache, bool doNotLockFile, bool getDebugInfo, bool useStaticCache, bool preserveShortBranches) {
      Debug.Assert(buffer != null);
      if (localAssemblyCache == null) localAssemblyCache = new Hashtable();
      this.localAssemblyCache = localAssemblyCache;
      this.getDebugSymbols = getDebugInfo;
      this.doNotLockFile = false;
      this.useStaticCache = useStaticCache;
      this.preserveShortBranches = preserveShortBranches;
      int n = this.bufferLength = buffer.Length;
      this.unmanagedBuffer = new UnmanagedBuffer(n);
      //^ base();
      byte* pb = (byte*)this.unmanagedBuffer.Pointer;
      for (int i = 0; i < n; i++) *pb++ = buffer[i];
    }
#endif
    internal Reader(string/*!*/ fileName, IDictionary localAssemblyCache, bool doNotLockFile, bool getDebugInfo, bool useStaticCache, bool preserveShortBranches){
      if (localAssemblyCache == null) localAssemblyCache = new Hashtable();
      this.localAssemblyCache = localAssemblyCache;
      fileName = System.IO.Path.GetFullPath(fileName);
      this.fileName = fileName;
      this.directory = System.IO.Path.GetDirectoryName(fileName);
      this.getDebugSymbols = getDebugInfo;
      this.doNotLockFile = doNotLockFile;
      this.useStaticCache = useStaticCache;
      this.preserveShortBranches = preserveShortBranches;
      //^ base();
    }
    internal Reader(IDictionary localAssemblyCache, bool doNotLockFile, bool getDebugInfo, bool useStaticCache, bool preserveShortBranches){
      if (localAssemblyCache == null) localAssemblyCache = new Hashtable();
      this.localAssemblyCache = localAssemblyCache;
      this.directory = System.IO.Directory.GetCurrentDirectory();
      this.getDebugSymbols = getDebugInfo;
      this.doNotLockFile = doNotLockFile;
      this.useStaticCache = useStaticCache;
      this.preserveShortBranches = preserveShortBranches;
      //^ base();
    }
    public void Dispose(){
      if (this.unmanagedBuffer != null)
        this.unmanagedBuffer.Dispose();
      this.unmanagedBuffer = null;
      if (this.tables != null)
        this.tables.Dispose();
      //this.tables = null;
#if !ROTOR && !UseSingularityPDB
      if (this.debugReader != null)
        Marshal.ReleaseComObject(this.debugReader);
      this.debugReader = null;
      this.debugDocuments = null;
#endif
    }
    private unsafe void SetupReader(){
      Debug.Assert(this.localAssemblyCache != null);
#if !ROTOR
      if (this.doNotLockFile){
#endif
        using (System.IO.FileStream inputStream = new System.IO.FileStream(this.fileName, 
                 System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read)){
          this.ReadFileIntoUnmanagedBuffer(inputStream);
        }
#if !ROTOR
      }
      if (this.unmanagedBuffer == null)
        this.tables = new MetadataReader(this.fileName); //Uses a memory map that locks the file
      else
#endif
        this.tables = new MetadataReader((byte*)this.unmanagedBuffer.Pointer, this.bufferLength);
      //^ assume this.tables.tablesHeader != null;
      this.sortedTablesMask = this.tables.tablesHeader.maskSorted;
    }
#if !ROTOR
    [DllImport("kernel32", SetLastError=true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern unsafe bool ReadFile(IntPtr FileHandle, byte* Buffer, int NumberOfBytesToRead, int* NumberOfBytesRead, IntPtr Overlapped);
#endif
    private unsafe void ReadFileIntoUnmanagedBuffer(System.IO.FileStream/*!*/ inputStream) {
      long size = inputStream.Seek(0, System.IO.SeekOrigin.End);
      if (size > int.MaxValue) throw new System.IO.FileLoadException();
      inputStream.Seek(0, System.IO.SeekOrigin.Begin);
      int n = (int)size;
      this.bufferLength = n;
      this.unmanagedBuffer = new UnmanagedBuffer(n);
      byte* pb = (byte*)this.unmanagedBuffer.Pointer;
#if !ROTOR
#if WHIDBEY && !OldWhidbey
      if (!Reader.ReadFile(inputStream.SafeFileHandle.DangerousGetHandle(), pb, n, &n, IntPtr.Zero)) throw new System.IO.FileLoadException();
#else
      if (!Reader.ReadFile(inputStream.Handle, pb, n, &n, IntPtr.Zero)) throw new System.IO.FileLoadException();
#endif
#else
      //Read a fixed length block at a time, so that the GC does not come under pressure from lots of large byte arrays.
      int bufferLen = 8096;
      byte[] buffer = new byte[bufferLen];
      while (n > 0){
        if (n < bufferLen) bufferLen = n;
        inputStream.Read(buffer, 0, bufferLen);
        for (int i = 0; i < bufferLen; i++) *pb++ = buffer[i];
        n -= bufferLen;
      }
#endif
    }
    internal void SetupDebugReader(string filename, string pdbSearchPath){
#if CodeContracts
      string pdbFileName = BetterPath.ChangeExtension(filename, "pdb");
      this.getDebugSymbolsFailed = true;
      //TODO: use search path
      if (System.IO.File.Exists(pdbFileName))
      {
        using (System.IO.FileStream inputStream = new System.IO.FileStream(pdbFileName,
                 System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read))
        {
          this.pdbInfo = new PdbInfo(inputStream, this);
          this.getDebugSymbolsFailed = false;
        }
      }
#endif
#if UseSingularityPDB
      string pdbFileName = BetterPath.ChangeExtension(filename, "pdb");
      this.getDebugSymbolsFailed = true;
      //TODO: use search path
      if (System.IO.File.Exists(pdbFileName)) {
        using (System.IO.FileStream inputStream = new System.IO.FileStream(pdbFileName,
                 System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read)) {
          this.pdbFunctions = PdbFile.LoadFunctions(inputStream, true);
          this.getDebugSymbolsFailed = false;
        }
      }
#elif !ROTOR
      if (filename == null) return;
      CorSymBinder binderObj1 = null;
      CorSymBinder2 binderObj2 = null;
      getDebugSymbolsFailed = false;
      object importer = null;
      try{
        int hresult = 0;
        try{
          binderObj2 = new CorSymBinder2();
          ISymUnmanagedBinder2 binder2 = (ISymUnmanagedBinder2)binderObj2;
#if !NoWriter          
            importer = new Ir2md(new Module());
#else
            importer = new EmptyImporter();
#endif
          hresult = binder2.GetReaderForFile(importer, filename, pdbSearchPath, out this.debugReader);
        }
        catch (COMException e){
          // could not instantiate ISymUnmanagedBinder2, fall back to ISymUnmanagedBinder
          if ((uint)e.ErrorCode == 0x80040111){
            binderObj1 = new CorSymBinder();
            ISymUnmanagedBinder binder = (ISymUnmanagedBinder)binderObj1;
            hresult = binder.GetReaderForFile(importer, filename, null, out this.debugReader);
          }else{
            throw;
          }
        }
        switch ((uint)hresult){
          case 0x0: break; 
          case 0x806d0005:  // EC_NOT_FOUND
          case 0x806d0014 : // EC_INVALID_EXE_TIMESTAMP
#if FxCop
            this.getDebugSymbols = false;
            this.getDebugSymbolsFailed = true;
#else
            // Sometimes GetReaderForFile erroneously reports missing pdb files as being "out of date", 
            // so we check if the file actually exists before reporting the error.
            // The mere absence of a pdb file is not an error. If not present, do not report.
            if (System.IO.File.Exists(System.IO.Path.ChangeExtension(filename, ".pdb")))
              throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, ExceptionStrings.PdbAssociatedWithFileIsOutOfDate, filename));
#endif            
            break;
          default:
            throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, 
              ExceptionStrings.GetReaderForFileReturnedUnexpectedHResult, hresult.ToString("X")));
        }
#if !FxCop
      }catch (Exception e){
        this.getDebugSymbols = false;
        this.getDebugSymbolsFailed = true;
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
#endif
      }finally{
        if (binderObj1 != null) Marshal.ReleaseComObject(binderObj1);
        if (binderObj2 != null) Marshal.ReleaseComObject(binderObj2);
      }
#endif // !ROTOR
    }
#if !MinimalReader
    private AssemblyNode ReadAssembly()
    {
      return ReadAssembly(null);
    }
    private AssemblyNode ReadAssembly(AssemblyNode.PostAssemblyLoadProcessor postLoadEvent){
#else
    private AssemblyNode ReadAssembly(){
#endif
      try{
        AssemblyNode assembly = new AssemblyNode(new Module.TypeNodeProvider(this.GetTypeFromName), 
          new Module.TypeNodeListProvider(this.GetTypeList), new Module.CustomAttributeProvider(this.GetCustomAttributesFor),
          new Module.ResourceProvider(this.GetResources), this.directory);
        assembly.reader = this;
        this.ReadModuleProperties(assembly);
        this.ReadAssemblyProperties(assembly); //Hashvalue, Name, etc.
        this.module = assembly;
        this.ReadAssemblyReferences(assembly);
        this.ReadModuleReferences(assembly);
        AssemblyNode cachedAssembly = this.GetCachedAssembly(assembly);
        if (cachedAssembly != null) return cachedAssembly;
        if (this.getDebugSymbols) assembly.SetupDebugReader(null);
#if !MinimalReader
        if (postLoadEvent != null) {
          assembly.AfterAssemblyLoad += postLoadEvent;
          postLoadEvent(assembly);
        }
#endif
        return assembly;
#if !FxCop
      }
      catch(Microsoft.Cci.Pdb.NoNameStreamPdbException e)
      {
        if (this.module == null) return null;
        if (this.module.MetadataImportWarnings == null) this.module.MetadataImportWarnings = new ArrayList();
        this.module.MetadataImportWarnings.Add(e);
        return this.module as AssemblyNode;
      }
      catch(Exception e){
        if (this.module == null) return null;
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
        return this.module as AssemblyNode;
      }
#else
      }finally{}
#endif
    }
    private AssemblyNode GetCachedAssembly(AssemblyNode/*!*/ assembly) {
      //Always return the one true mscorlib. Things get too weird if more than one mscorlib is being read at the same time.
      //if (CoreSystemTypes.SystemAssembly != null && CoreSystemTypes.SystemAssembly.Name == assembly.Name && CoreSystemTypes.SystemAssembly.reader != null) {
      //  if (CoreSystemTypes.SystemAssembly.reader != this) {
      //    if (this.getDebugSymbols && !CoreSystemTypes.SystemAssembly.reader.getDebugSymbols && !CoreSystemTypes.SystemAssembly.reader.getDebugSymbolsFailed)
      //      CoreSystemTypes.SystemAssembly.SetupDebugReader(null);
      //    this.Dispose();
      //  }
      //  return CoreSystemTypes.SystemAssembly;
      //}
      if (assembly.PublicKeyOrToken == null || assembly.PublicKeyOrToken.Length == 0){
        AssemblyNode cachedAssembly = null;
        if (assembly.Location != null)
          cachedAssembly = this.localAssemblyCache[assembly.Location] as AssemblyNode;
        if (cachedAssembly == null && assembly.Name != null){
          cachedAssembly = this.localAssemblyCache[assembly.Name] as AssemblyNode;
          if (cachedAssembly != null && assembly.Location != null)
            this.localAssemblyCache[assembly.Location] = cachedAssembly;
        }
        if (cachedAssembly != null) {
          if (cachedAssembly.reader != this && cachedAssembly.reader != null){
            if (this.getDebugSymbols && !cachedAssembly.reader.getDebugSymbols && !cachedAssembly.reader.getDebugSymbolsFailed)
              cachedAssembly.SetupDebugReader(null);
            this.Dispose();
          }
          return cachedAssembly;
        }
        lock (Reader.StaticAssemblyCache) {
          if (assembly.Name != null)
            this.localAssemblyCache[assembly.Name] = assembly;
          if (this.fileName != null)
            this.localAssemblyCache[this.fileName] = assembly;
        }
      }else{
        string assemblyStrongName = assembly.StrongName;
        AssemblyNode cachedAssembly = null;
        if (this.useStaticCache){
          //See if assembly is a platform assembly (and apply unification)
          AssemblyReference assemblyReference = new AssemblyReference(assembly);
          AssemblyReference aRef = (AssemblyReference)TargetPlatform.AssemblyReferenceFor[Identifier.For(assemblyReference.Name).UniqueIdKey];
          if (aRef != null && assemblyReference.Version != null && aRef.Version >= assemblyReference.Version && aRef.MatchesIgnoringVersion(assemblyReference)) {
            AssemblyNode platformAssembly = aRef.assembly;
            if (platformAssembly == null) {
              Debug.Assert(aRef.Location != null);
              if (Path.GetFullPath(aRef.Location) == assembly.Location) {
                if (aRef.Version != assemblyReference.Version) {
                  HandleError(assembly, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.BadTargetPlatformLocation, assembly.Name, TargetPlatform.PlatformAssembliesLocation, assembly.Version, aRef.Version));
                }
                lock (Reader.StaticAssemblyCache) {
                  Reader.StaticAssemblyCache[assemblyStrongName] = assembly;
                  if (aRef.Location != null)
                    Reader.StaticAssemblyCache[aRef.Location] = assembly;
                  aRef.Assembly = assembly;
                }
                return null; //Prevents infinite recursion
              }
              platformAssembly = AssemblyNode.GetAssembly(aRef.Location, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
            }
            if (platformAssembly != null) {
              lock (Reader.StaticAssemblyCache) {
                if (aRef.Location != null)
                  Reader.StaticAssemblyCache[aRef.Location] = platformAssembly;
                Reader.StaticAssemblyCache[assemblyStrongName] = platformAssembly;
              }
              return aRef.assembly = platformAssembly;
            }
          }
          cachedAssembly = Reader.StaticAssemblyCache[assemblyStrongName] as AssemblyNode;
          if (cachedAssembly != null){
            if (aRef == null && assembly.FileLastWriteTimeUtc > cachedAssembly.FileLastWriteTimeUtc &&
              assembly.Location != null && cachedAssembly.Location != null && assembly.Location == cachedAssembly.Location) {
              lock (Reader.StaticAssemblyCache) {
                Reader.StaticAssemblyCache[assemblyStrongName] = assembly;
              }
              return null;
            }
            if (cachedAssembly.reader != this && cachedAssembly.reader != null){
              if (this.getDebugSymbols && !cachedAssembly.reader.getDebugSymbols && !cachedAssembly.reader.getDebugSymbolsFailed)
                cachedAssembly.SetupDebugReader(null);
              this.Dispose();
            }
            return cachedAssembly;
          }
          lock (Reader.StaticAssemblyCache) {
            Reader.StaticAssemblyCache[assemblyStrongName] = assembly;
            if (this.fileName != null) {
              Reader.StaticAssemblyCache[this.fileName] = assembly;
            }
          }
        }else{
          cachedAssembly = this.localAssemblyCache[assemblyStrongName] as AssemblyNode;
          if (cachedAssembly != null) {
            if (assembly.FileLastWriteTimeUtc > cachedAssembly.FileLastWriteTimeUtc &&
              assembly.Location != null && cachedAssembly.Location != null && assembly.Location == cachedAssembly.Location) {
              this.localAssemblyCache[assemblyStrongName] = assembly;
              return null;
            }
            if (cachedAssembly.reader != this && cachedAssembly.reader != null) {
#if UseSingularityPDB
              if (this.getDebugSymbols && cachedAssembly.reader.pdbFunctions == null && !cachedAssembly.reader.getDebugSymbolsFailed)
                cachedAssembly.SetupDebugReader(null);
#elif !ROTOR
              if (this.getDebugSymbols && cachedAssembly.reader.debugReader == null && !cachedAssembly.reader.getDebugSymbolsFailed)
                cachedAssembly.SetupDebugReader(null);
#endif
              this.Dispose();
            }
            return cachedAssembly;
          }
          this.localAssemblyCache[assemblyStrongName] = assembly;
          if (this.fileName != null) this.localAssemblyCache[this.fileName] = assembly;
        }
      }
      return null;
    }
#if !MinimalReader
    internal Module ReadModule()
    {
      return ReadModule(null);
    }
    internal Module ReadModule(AssemblyNode.PostAssemblyLoadProcessor postLoadEvent){
#else
    internal Module ReadModule(){
#endif
      try{
        if (this.fileName != null){
          if (!System.IO.File.Exists(this.fileName)) return null;
          AssemblyNode cachedAssembly;
          if (this.useStaticCache) {
            cachedAssembly = Reader.StaticAssemblyCache[this.fileName] as AssemblyNode;
            if (cachedAssembly != null && cachedAssembly.FileLastWriteTimeUtc == System.IO.File.GetLastWriteTimeUtc(this.fileName)) {
              this.Dispose();
              return cachedAssembly;
            }
          }
          cachedAssembly = this.localAssemblyCache[this.fileName] as AssemblyNode;
          if (cachedAssembly != null && cachedAssembly.FileLastWriteTimeUtc == System.IO.File.GetLastWriteTimeUtc(this.fileName)) {
            this.Dispose();
            return cachedAssembly;
          }
        }
        this.SetupReader();
        if (this.tables.AssemblyTable.Length > 0)
#if !MinimalReader
          return this.ReadAssembly(postLoadEvent);
#else
          return this.ReadAssembly();
#endif
        Module module = this.module = new Module(new Module.TypeNodeProvider(this.GetTypeFromName), 
          new Module.TypeNodeListProvider(this.GetTypeList), new Module.CustomAttributeProvider(this.GetCustomAttributesFor),
          new Module.ResourceProvider(this.GetResources));
        module.reader = this;
        this.ReadModuleProperties(module);
        this.module = module;
        this.ReadAssemblyReferences(module);
        this.ReadModuleReferences(module);
        if (this.getDebugSymbols) this.SetupDebugReader(this.fileName, null);
        return module;
#if !FxCop
      }catch(Exception e){
        if (this.module == null) return null;
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
        return module;
      }
#else
      }finally{}
#endif
    }
    private void ReadModuleProperties(Module/*!*/ module){
      ModuleRow[] mods = this.tables.ModuleTable;
      if (mods.Length != 1) throw new InvalidMetadataException(ExceptionStrings.InvalidModuleTable);
      ModuleRow mrow = mods[0];
      module.reader = this;
      module.DllCharacteristics = this.tables.dllCharacteristics;
      module.FileAlignment = this.tables.fileAlignment;
      module.BaseAddress = this.tables.baseAddress;
      module.SizeOfStackReserve = this.tables.sizeOfStackReserve;
      module.HashValue = this.tables.HashValue;
      module.Kind = this.tables.moduleKind;
      module.Location = this.fileName;
      module.TargetRuntimeVersion = this.tables.targetRuntimeVersion;
      module.LinkerMajorVersion = this.tables.linkerMajorVersion;
      module.LinkerMinorVersion = this.tables.linkerMinorVersion;
      module.MetadataFormatMajorVersion = this.tables.metadataFormatMajorVersion;
      module.MetadataFormatMinorVersion = this.tables.metadataFormatMinorVersion;
      module.Name = this.tables.GetString(mrow.Name);
      module.Mvid = this.tables.GetGuid(mrow.Mvid);
      module.PEKind = this.tables.peKind;
      module.TrackDebugData = this.tables.TrackDebugData;
    }
    private void ReadAssemblyProperties(AssemblyNode/*!*/ assembly) {
      AssemblyRow assemblyRow = this.tables.AssemblyTable[0];
      assembly.HashAlgorithm = (AssemblyHashAlgorithm)assemblyRow.HashAlgId;
      assembly.Version = new System.Version(assemblyRow.MajorVersion, assemblyRow.MinorVersion, assemblyRow.BuildNumber, assemblyRow.RevisionNumber);
      assembly.Flags = (AssemblyFlags)assemblyRow.Flags;
      assembly.PublicKeyOrToken = this.tables.GetBlob(assemblyRow.PublicKey);
      assembly.ModuleName = assembly.Name;
      assembly.Name = this.tables.GetString(assemblyRow.Name);
      assembly.Culture = this.tables.GetString(assemblyRow.Culture);
      if (this.fileName != null){
        assembly.FileLastWriteTimeUtc = System.IO.File.GetLastWriteTimeUtc(this.fileName);
      }
      assembly.ContainingAssembly = assembly;
    }
    private void ReadAssemblyReferences(Module/*!*/ module) {
      AssemblyRefRow[] assems = this.tables.AssemblyRefTable;
      int n = assems.Length;
      AssemblyReferenceList assemblies = module.AssemblyReferences = new AssemblyReferenceList(n);
      for (int i = 0; i < n; i++){
        AssemblyRefRow arr = assems[i];
        AssemblyReference assemRef = new AssemblyReference();
        assemRef.Version = new System.Version(arr.MajorVersion, arr.MinorVersion, arr.BuildNumber, arr.RevisionNumber);
        assemRef.Flags = (AssemblyFlags)arr.Flags;
        assemRef.PublicKeyOrToken = this.tables.GetBlob(arr.PublicKeyOrToken);
        assemRef.Name = this.tables.GetString(arr.Name);
        //if (CoreSystemTypes.SystemAssembly != null && CoreSystemTypes.SystemAssembly.Name == assemRef.Name && 
        //  assemRef.Version > CoreSystemTypes.SystemAssembly.Version){
        //  HandleError(module, ExceptionStrings.ModuleOrAssemblyDependsOnMoreRecentVersionOfCoreLibrary);
        //}
        assemRef.Culture = this.tables.GetString(arr.Culture);
        if (assemRef.Culture != null && assemRef.Culture.Length == 0) assemRef.Culture = null;
        assemRef.HashValue = this.tables.GetBlob(arr.HashValue);
        assemRef.Reader = this;
        assems[i].AssemblyReference = assemRef;
        assemblies.Add(assemRef);
      }
    }
    private void ReadModuleReferences(Module/*!*/ module) {
      FileRow[] files = this.tables.FileTable;
      ModuleRefRow[] modRefs = this.tables.ModuleRefTable;
      int n = modRefs.Length;
      ModuleReferenceList modules = module.ModuleReferences = new ModuleReferenceList(n);
      for (int i = 0; i < n; i++){
        Module mod;
        int nameIndex = modRefs[i].Name;
        string name = this.tables.GetString(nameIndex);
        string dir = BetterPath.GetDirectoryName(this.module.Location);
        string location = BetterPath.Combine(dir, name);
        for (int j = 0, m = files == null ? 0 : files.Length; j < m; j++){
          if (files[j].Name != nameIndex) continue;
          if ((files[j].Flags & (int)FileFlags.ContainsNoMetaData) == 0)
            mod = Module.GetModule(location, this.doNotLockFile, this.getDebugSymbols, false);
          else
            mod = null;
          if (mod == null){
            mod = new Module();
            mod.Name = name;
            mod.Location = location;
            mod.Kind = ModuleKindFlags.UnmanagedDynamicallyLinkedLibrary;
          }
          mod.HashValue = this.tables.GetBlob(files[j].HashValue);
          mod.ContainingAssembly = module.ContainingAssembly;
          modRefs[i].Module = mod;
          modules.Add(new ModuleReference(name, mod));
          goto nextModRef;
        }        
        mod = new Module();
        mod.Name = name;
        mod.Kind = ModuleKindFlags.UnmanagedDynamicallyLinkedLibrary;
        if (System.IO.File.Exists(location)) mod.Location = location;
        mod.ContainingAssembly = module.ContainingAssembly;
        modRefs[i].Module = mod;
        modules.Add(new ModuleReference(name, mod));
      nextModRef:;
      }
    }
    private static string ReadSerString(MemoryCursor/*!*/ sigReader) {
      int n = sigReader.ReadCompressedInt();
      if (n < 0) return null;
      return sigReader.ReadUTF8(n);
    }
    private void AddFieldsToType(TypeNode/*!*/ type, FieldRow[]/*!*/ fieldDefs, FieldPtrRow[]/*!*/ fieldPtrs, int start, int end) {
      for (int i = start; i < end; i++){
        int ii = i;
        if (fieldPtrs.Length > 0) ii = fieldPtrs[i-1].Field;
        Field field = this.GetFieldFromDef(ii, type);
        if (field != null) type.Members.Add(field);
      }
    }
    private void GetUnderlyingTypeOfEnumNode(EnumNode /*!*/enumNode, FieldRow[]/*!*/ fieldDefs, FieldPtrRow[]/*!*/ fieldPtrs, int start, int end) {
      TypeNode underlyingType = null;
      for (int i = start; i < end; i++){
        int ii = i;
        if (fieldPtrs.Length > 0) ii = fieldPtrs[i-1].Field;
        FieldRow fld = fieldDefs[ii-1];
        if (fld.Field != null && !fld.Field.IsStatic){
          underlyingType = fld.Field.Type;
          break;
        }
        FieldFlags fieldFlags = (FieldFlags)fld.Flags;
        if ((fieldFlags & FieldFlags.Static) == 0){
          this.tables.GetSignatureLength(fld.Signature);
          MemoryCursor sigReader = this.tables.GetNewCursor();          
          GetAndCheckSignatureToken(6, sigReader);
          underlyingType = this.ParseTypeSignature(sigReader);
          break;
        }
      }
      enumNode.underlyingType = underlyingType;
    }
    private void AddMethodsToType(TypeNode/*!*/ type, MethodPtrRow[]/*!*/ methodPtrs, int start, int end)
      //^ requires type.members != null;
    {
      for (int i = start; i < end; i++){
        int ii = i;
        if (methodPtrs.Length > 0) ii = methodPtrs[i-1].Method;
        Method method = this.GetMethodFromDef(ii, type);
        if (method != null && ((method.Flags & MethodFlags.RTSpecialName) == 0 || method.Name.UniqueIdKey != StandardIds._Deleted.UniqueIdKey))
          type.members.Add(method);
      }
    }
    private void AddMoreStuffToParameters(Method method, ParameterList parameters, int start, int end) {
      ParamRow[] pars = this.tables.ParamTable;
      int n = parameters == null ? 0 : parameters.Count;
      for (int i = start; i < end; i++){
        ParamRow pr = pars[i-1];
        if (pr.Sequence == 0 && method != null){
          //The parameter entry with sequence 0 is used as a target for custom attributes that apply to the return value
          method.ReturnAttributes = this.GetCustomAttributesFor((i << 5)|4);
          if ((pr.Flags & (int)ParameterFlags.HasFieldMarshal) != 0)
            method.ReturnTypeMarshallingInformation = this.GetMarshallingInformation((i << 1)|1);
          this.AddMoreStuffToParameters(null, parameters, start+1, end); 
          return;
        }
        int j = pr.Sequence;
        if (j < 1 || j > n) continue; //Bad metadata, ignore
        if (parameters == null) continue;
        Parameter par = parameters[j-1];
        par.Attributes = this.GetCustomAttributesFor((i << 5)|4);
        par.Flags = (ParameterFlags)pr.Flags;
        if ((par.Flags & ParameterFlags.HasDefault) != 0) 
          par.DefaultValue = this.GetLiteral((i << 2)|1, par.Type);
        if ((par.Flags & ParameterFlags.HasFieldMarshal) != 0)
          par.MarshallingInformation = this.GetMarshallingInformation((i << 1)|1);
        par.Name = tables.GetIdentifier(pr.Name);
#if ExtendedRuntime
        for (int k = 0, al = par.Attributes == null ? 0 : par.Attributes.Count; k < al; k++) {
          if (par.Attributes[k].Type == ExtendedRuntimeTypes.NotNullAttribute) {
            Reference r = par.Type as Reference;
            if (r != null){
              // need to make it a reference to a non-null type and not a non-null wrapper around the reference
              // also *must* make it a new Reference.
              OptionalModifier om = OptionalModifier.For(ExtendedRuntimeTypes.NonNullType, r.ElementType);
              par.Type = om.GetReferenceType();
            }else{
              par.Type = OptionalModifier.For(ExtendedRuntimeTypes.NonNullType, par.Type);
            }
            // Someone putting an attribute directly on the "real" method is still a
            // kind of out-of-band contract.
            // This marking is the way to signal that any override or implementing method being compiled
            // should not have its non-null annotations persisted as optional modifiers.
            par.DeclaringMethod.HasOutOfBandContract = true;
          } else if (par.Attributes[k].Type == ExtendedRuntimeTypes.NotNullArrayElementsAttribute) {
            Stack s = new Stack();
            Reference r = par.Type as Reference;
            TypeNode t;
            if (r != null) {
              // need to make it a reference to an array of non-null type and not a non-null wrapper around the reference
              t = r.ElementType;
            }
            else {
              t = par.Type;
            }
            while (t is OptionalModifier) {
              OptionalModifier om = t as OptionalModifier;
              s.Push(om.Modifier);
              t = om.ModifiedType;
            }
            ArrayType at = t as ArrayType;
            if (at != null) { // just silently ignore if attribute is on a non-array type?
              TypeNode newTypeForParameter;
              OptionalModifier om = OptionalModifier.For(ExtendedRuntimeTypes.NonNullType, at.ElementType);
              while (0 < s.Count) {
                om = OptionalModifier.For((TypeNode)s.Pop(), om);
              }
              // also *must* make it a new array type, can't set the ElementType.
              newTypeForParameter = om.GetArrayType(1);
              if (r != null) {
                // also *must* make it a new Reference, can't set the ElementType.
                newTypeForParameter = newTypeForParameter.GetReferenceType();
              }
              par.Type = newTypeForParameter;
              // Someone putting an attribute directly on the "real" method is still a
              // kind of out-of-band contract.
              // This marking is the way to signal that any override or implementing method being compiled
              // should not have its non-null annotations persisted as optional modifiers.
              par.DeclaringMethod.HasOutOfBandContract = true;
            }
          }
        }
#endif
      }
    }
    private void AddPropertiesToType(TypeNode/*!*/ type, PropertyRow[]/*!*/ propertyDefs, PropertyPtrRow[]/*!*/ propertyPtrs, int start, int end) 
      //requires type.members != null;
    {
      MetadataReader tables = this.tables;
      for (int i = start; i < end; i++){
        int ii = i;
        if (propertyPtrs.Length > 0) ii = propertyPtrs[i-1].Property;
        PropertyRow prop = propertyDefs[ii-1];
        Property property = new Property();
        property.Attributes = this.GetCustomAttributesFor((ii << 5)|9);
        property.DeclaringType = type;
        property.Flags = (PropertyFlags)prop.Flags;
        property.Name = tables.GetIdentifier(prop.Name);
        if ((property.Flags & PropertyFlags.RTSpecialName) == 0 || property.Name.UniqueIdKey != StandardIds._Deleted.UniqueIdKey){
          this.AddMethodsToProperty(ii, property);
          type.members.Add(property);
        }
        //REVIEW: the signature seems to be redundant. Is there any point in retrieving it?
      }
    }
    private void AddMethodsToProperty(int propIndex, Property/*!*/ property) {
      int codedPropIndex = (propIndex << 1) | 1;
      MetadataReader tables = this.tables;
      MethodRow[] methods = tables.MethodTable;
      MethodSemanticsRow[] methodSemantics = tables.MethodSemanticsTable;
      int i = 0, n = methodSemantics.Length, j = n-1;
      bool sorted = (this.sortedTablesMask >> (int)TableIndices.MethodSemantics) % 2 == 1;
      if (sorted){
        while (i < j){
          int k = (i+j) / 2;
          if (methodSemantics[k].Association < codedPropIndex)
            i = k+1;
          else
            j = k;
        }
        while (i > 0 && methodSemantics[i-1].Association == codedPropIndex) i--;
      }
      for (; i < n; i++){
        MethodSemanticsRow meth = methodSemantics[i];
        Method propertyMethod = methods[meth.Method-1].Method;
        if (propertyMethod == null) continue;
        if (meth.Association == codedPropIndex){
          propertyMethod.DeclaringMember = property;
          switch(meth.Semantics){
            case 0x0001 : property.Setter = propertyMethod; break;
            case 0x0002 : property.Getter = propertyMethod; break;
            default:
              if (property.OtherMethods == null) property.OtherMethods = new MethodList();
              property.OtherMethods.Add(propertyMethod); break;
          }
        }else if (sorted)
          break;
      }
    }
    private void AddEventsToType(TypeNode/*!*/ type, EventRow[]/*!*/ eventDefs, EventPtrRow[]/*!*/ eventPtrs, int start, int end) {
      MetadataReader tables = this.tables;
      for (int i = start; i < end; i++){
        int ii = i;
        if (eventPtrs.Length > 0) ii = eventPtrs[i].Event;
        EventRow ev = eventDefs[ii-1];
        Event evnt = new Event();
        evnt.Attributes = this.GetCustomAttributesFor((ii << 5)|10);
        evnt.DeclaringType = type;
        evnt.Flags = (EventFlags)ev.Flags;
        evnt.HandlerType = this.DecodeAndGetTypeDefOrRefOrSpec(ev.EventType);
        evnt.Name = tables.GetIdentifier(ev.Name);
        if ((evnt.Flags & EventFlags.RTSpecialName) == 0 || evnt.Name.UniqueIdKey != StandardIds._Deleted.UniqueIdKey){
          this.AddMethodsToEvent(ii, evnt);
          type.Members.Add(evnt);
        }
      }
    }
    private void AddMethodsToEvent(int eventIndex, Event/*!*/ evnt) {
      int codedEventIndex = eventIndex << 1;
      MetadataReader tables = this.tables;
      MethodRow[] methods = tables.MethodTable;
      MethodSemanticsRow[] methodSemantics = tables.MethodSemanticsTable;
      int i = 0, n = methodSemantics.Length, j = n-1;
      bool sorted = (this.sortedTablesMask >> (int)TableIndices.MethodSemantics) % 2 == 1;
      if (sorted){
        while (i < j){
          int k = (i+j) / 2;
          if (methodSemantics[k].Association < codedEventIndex)
            i = k+1;
          else
            j = k;
        }
        while (i > 0 && methodSemantics[i-1].Association == codedEventIndex) i--;
      }
      MethodFlags handlerFlags = (MethodFlags)0;
      for (; i < n; i++){
        MethodSemanticsRow meth = methodSemantics[i];
        Method eventMethod = methods[meth.Method-1].Method;
        if (eventMethod == null) continue;
        if (meth.Association == codedEventIndex){
          eventMethod.DeclaringMember = evnt;
          switch(meth.Semantics){
            case 0x0008: evnt.HandlerAdder = eventMethod; handlerFlags = eventMethod.Flags; break;
            case 0x0010: evnt.HandlerRemover = eventMethod; handlerFlags = eventMethod.Flags; break;
            case 0x0020: evnt.HandlerCaller = eventMethod; break;
            default:
              if (evnt.OtherMethods == null) evnt.OtherMethods = new MethodList();
              evnt.OtherMethods.Add(eventMethod); break;
          }
        }else if (sorted)
          break;
      }
      evnt.HandlerFlags = handlerFlags;
    }
    private bool TypeDefOrRefOrSpecIsClass(int codedIndex){
      if (codedIndex == 0) return false;
      switch(codedIndex & 0x3){
        case 0x00 : return this.TypeDefIsClass(codedIndex >> 2);
        case 0x01 : TypeNode t = this.GetTypeFromRef(codedIndex >> 2); return t is Class;
        case 0x02 : return this.TypeSpecIsClass(codedIndex >> 2);
      }
      throw new InvalidMetadataException(ExceptionStrings.BadTypeDefOrRef);
    }
    private bool TypeDefOrRefOrSpecIsClassButNotValueTypeBaseClass(int codedIndex){
      if (codedIndex == 0) return false;
      switch (codedIndex & 0x3) {
        case 0x00: return this.TypeDefIsClassButNotValueTypeBaseClass(codedIndex >> 2);
        case 0x01: 
          TypeNode t = this.GetTypeFromRef(codedIndex >> 2); 
          return t != CoreSystemTypes.ValueType && t != CoreSystemTypes.Enum && t is Class;
        case 0x02: return this.TypeSpecIsClass(codedIndex >> 2);
      }
      throw new InvalidMetadataException(ExceptionStrings.BadTypeDefOrRef);
    }
    private TypeNode DecodeAndGetTypeDefOrRefOrSpec(int codedIndex) {
      if (codedIndex == 0) return null;
      switch(codedIndex & 0x3){
        case 0x00 : return this.GetTypeFromDef(codedIndex >> 2);
        case 0x01 : return this.GetTypeFromRef(codedIndex >> 2);
        case 0x02 : return this.GetTypeFromSpec(codedIndex >> 2);
      }
      throw new InvalidMetadataException(ExceptionStrings.BadTypeDefOrRef);
    }
    private TypeNode DecodeAndGetTypeDefOrRefOrSpec(int codedIndex, bool expectStruct) {
      if (codedIndex == 0) return null;
      switch(codedIndex & 0x3){
        case 0x00 : return this.GetTypeFromDef(codedIndex >> 2);
        case 0x01 : return this.GetTypeFromRef(codedIndex >> 2, expectStruct);
        case 0x02 : return this.GetTypeFromSpec(codedIndex >> 2);
      }
      throw new InvalidMetadataException(ExceptionStrings.BadTypeDefOrRef);
    }
#if ExtendedRuntime
    private Interface GetInterfaceIfNotGenericInstance(int codedIndex){
      if (codedIndex == 0) return null;
      switch(codedIndex & 0x3){
        case 0x00 : return this.GetTypeFromDef(codedIndex >> 2) as Interface;
        case 0x01 : return this.GetTypeFromRef(codedIndex >> 2, false) as Interface;
      }
      return null;
    }
#endif
    private TypeNode GetTypeIfNotGenericInstance(int codedIndex){
      if (codedIndex == 0) return null;
      switch(codedIndex & 0x3){
        case 0x00 : return this.GetTypeFromDef(codedIndex >> 2);
        case 0x01 : return this.GetTypeFromRef(codedIndex >> 2, false);
      }
      return null;
    }
    internal AssemblyNode/*!*/ GetAssemblyFromReference(AssemblyReference/*!*/ assemblyReference) {
      lock (Module.GlobalLock) {
        if (SystemAssemblyLocation.ParsedAssembly != null && (assemblyReference.Name == "mscorlib" || assemblyReference.Name == "basetypes" || assemblyReference.Name == "ioconfig"
          || assemblyReference.Name == "singularity.v1" )) 
          return SystemAssemblyLocation.ParsedAssembly;
        if (CoreSystemTypes.SystemAssembly != null && CoreSystemTypes.SystemAssembly.Name == assemblyReference.Name) return CoreSystemTypes.SystemAssembly;
        string strongName = null;
        object cachedValue = null;
        if (assemblyReference.PublicKeyOrToken == null || assemblyReference.PublicKeyOrToken.Length == 0){
          if (assemblyReference.Location != null)
            cachedValue = this.localAssemblyCache[assemblyReference.Location];
          if (cachedValue == null){
            cachedValue = this.localAssemblyCache[assemblyReference.Name];
            if (cachedValue != null && assemblyReference.Location != null)
              this.localAssemblyCache[assemblyReference.Location] = cachedValue;
          }
        }else{
          strongName = assemblyReference.StrongName;
          if (this.useStaticCache){
            //See if reference is to an assembly that lives in the GAC.
            if (assemblyReference.Location != null)
              cachedValue = Reader.StaticAssemblyCache[assemblyReference.Location];
            if (cachedValue == null)
              cachedValue = Reader.StaticAssemblyCache[strongName];
          }
          if (cachedValue == null)
            cachedValue = this.localAssemblyCache[strongName];
        }
        if (cachedValue == null){
          //See if assembly is a platform assembly (and apply unification)
          AssemblyReference aRef = (AssemblyReference)TargetPlatform.AssemblyReferenceFor[Identifier.For(assemblyReference.Name).UniqueIdKey];
          if (aRef != null && assemblyReference.Version != null && aRef.Version >= assemblyReference.Version && aRef.MatchesIgnoringVersion(assemblyReference)){
            AssemblyNode platformAssembly = aRef.assembly;
            if (platformAssembly == null){
              Debug.Assert(aRef.Location != null);
#if MinimalReader
              platformAssembly = AssemblyNode.GetAssembly(aRef.Location, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
              platformAssembly = AssemblyNode.GetAssembly(aRef.Location, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            }
            if (platformAssembly != null){
              if (strongName == null) strongName = assemblyReference.Name;
              lock (Reader.StaticAssemblyCache) {
                if (aRef.Location != null)
                  Reader.StaticAssemblyCache[aRef.Location] = platformAssembly;
                Reader.StaticAssemblyCache[strongName] = platformAssembly;
              }
              aRef.assembly = platformAssembly;
              return platformAssembly;
            }
          }
        }
        AssemblyNode assembly = cachedValue as AssemblyNode;
        if (assembly != null) goto done;
      
        //No cached assembly and no cached reader for this assembly. Look for a resolver.
        if (this.module != null){
          assembly = this.module.Resolve(assemblyReference);
          if (assembly != null){
            if (strongName == null){
              this.localAssemblyCache[assembly.Name] = assembly;
              if (assembly.Location != null) this.localAssemblyCache[assembly.Location] = assembly;
            }else{
              if (CoreSystemTypes.SystemAssembly != null && CoreSystemTypes.SystemAssembly.Name == assembly.Name) return CoreSystemTypes.SystemAssembly;
              lock (Reader.StaticAssemblyCache) {
                if (this.useStaticCache) {
                  if (assembly.Location != null)
                    Reader.StaticAssemblyCache[assembly.Location] = assembly;
                  Reader.StaticAssemblyCache[strongName] = assembly;
                } else {
                  this.localAssemblyCache[strongName] = assembly;
                  if (assembly.Location != null) this.localAssemblyCache[assembly.Location] = assembly;
                }
              }
            }
            goto done;
          }
        }

        //Look for an assembly with the given name in the same directory as the referencing module
        if (this.directory != null){
          string fileName = System.IO.Path.Combine(this.directory, assemblyReference.Name+".dll");
          if (System.IO.File.Exists(fileName)){
#if MinimalReader
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            if (assembly != null)
            {
              if (strongName == null) goto cacheIt; //found something
              //return assembly only if it matches the strong name of the reference
              if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt;
            }            
          }
          fileName = System.IO.Path.Combine(this.directory, assemblyReference.Name+".exe");
          if (System.IO.File.Exists(fileName)){
#if MinimalReader
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            if (assembly != null)
            {
              if (strongName == null) goto cacheIt; //found something
              //return assembly only if it matches the strong name of the reference
              if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt;
            }            
          }
          fileName = System.IO.Path.Combine(this.directory, assemblyReference.Name+".winmd");
          if (System.IO.File.Exists(fileName)) {
#if MinimalReader
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            if (assembly != null) {
              if (strongName == null) goto cacheIt; //found something
              //return assembly only if it matches the strong name of the reference
              if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt;
            }
          }
          fileName = System.IO.Path.Combine(this.directory, assemblyReference.Name+".ill");
          if (System.IO.File.Exists(fileName)) {
#if MinimalReader
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            if (assembly != null)
            {
              if (strongName == null) goto cacheIt; //found something
              //return assembly only if it matches the strong name of the reference
              if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt;
            }
          }
        }
        //Look for an assembly in the same directory as the application using Reader.
        { string fileName = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assemblyReference.Name+".dll");
          if (System.IO.File.Exists(fileName)){
#if MinimalReader
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            if (assembly != null)
            {
              if (strongName == null) goto cacheIt; //found something
              //return assembly only if it matches the strong name of the reference
              if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt;
            }            
          }
          fileName = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assemblyReference.Name+".exe");
          if (System.IO.File.Exists(fileName)){
#if MinimalReader
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            if (assembly != null)
            {
              if (strongName == null) goto cacheIt; //found something
              //return assembly only if it matches the strong name of the reference
              if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt;
            }            
          }
          fileName = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assemblyReference.Name+".winmd");
          if (System.IO.File.Exists(fileName)) {
#if MinimalReader
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
            assembly = AssemblyNode.GetAssembly(fileName, this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            if (assembly != null) {
              if (strongName == null) goto cacheIt; //found something
              //return assembly only if it matches the strong name of the reference
              if (assemblyReference.Matches(assembly.Name, assembly.Version, assembly.Culture, assembly.PublicKeyToken)) goto cacheIt;
            }
          }
        }
        assembly = null;

        //Probe the GAC
#if FxCop
        if(probeGAC){
#endif
        string gacLocation = null;
        if (strongName != null){
#if !ROTOR
          //Look for the assembly in the system's Global Assembly Cache
          gacLocation = GlobalAssemblyCache.GetLocation(assemblyReference);
          if (gacLocation != null && gacLocation.Length == 0) gacLocation = null;
#else
          //TODO: look in the ROTOR GAC
#endif
          if (gacLocation != null){
#if MinimalReader
            assembly = AssemblyNode.GetAssembly(gacLocation, this.useStaticCache ? Reader.StaticAssemblyCache : this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache);
#else
            assembly = AssemblyNode.GetAssembly(gacLocation, this.useStaticCache ? Reader.StaticAssemblyCache : this.localAssemblyCache, this.doNotLockFile, this.getDebugSymbols, this.useStaticCache, this.ReferringAssemblyPostLoad);
#endif
            if (assembly != null)
            {
              lock (Reader.StaticAssemblyCache) {
                if (this.useStaticCache) {
                  Reader.StaticAssemblyCache[gacLocation] = assembly;
                  Reader.StaticAssemblyCache[strongName] = assembly;
                } else {
                  this.localAssemblyCache[gacLocation] = assembly;
                  this.localAssemblyCache[strongName] = assembly;
                }
              }
            }
          }
        }
#if FxCop
        }
#endif
        goto done;
      cacheIt:
        if (strongName == null){
          this.localAssemblyCache[assembly.Name] = assembly;
          if (assembly.Location != null) this.localAssemblyCache[assembly.Location] = assembly;
        }else{
          this.localAssemblyCache[strongName] = assembly;
          if (assembly.Location != null) this.localAssemblyCache[assembly.Location] = assembly;
        }
#if !MinimalReader
        // the post load event should fire when we load the assembly the first time
//        assembly.InitializePostAssemblyLoadAndFire(this.module);
#endif
      done:
        if (assembly != null)
          assembly.InitializeAssemblyReferenceResolution(this.module);
        if (assembly == null){
          if (this.module != null) {
            assembly = this.module.ResolveAfterProbingFailed(assemblyReference);
            if (assembly != null) goto cacheIt;
            HandleError(this.module, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.AssemblyReferenceNotResolved, assemblyReference.StrongName));
          }
          assembly = new AssemblyNode();
          assembly.Culture = assemblyReference.Culture;
          assembly.Name = assemblyReference.Name;
          assembly.PublicKeyOrToken = assemblyReference.PublicKeyOrToken;
          assembly.Version = assemblyReference.Version;
          assembly.Location = "unknown:location";
          goto cacheIt;
        }
        return assembly;
      }
    }
#if !MinimalReader
    private AssemblyNode.PostAssemblyLoadProcessor ReferringAssemblyPostLoad
    {
      get
      {
        AssemblyNode assem = this.module as AssemblyNode;
        if (assem == null) return null;
        return assem.GetAfterAssemblyLoad();
      }
    }
#endif
    private static void GetAndCheckSignatureToken(int expectedToken, MemoryCursor/*!*/ sigReader) {
      int tok = sigReader.ReadCompressedInt();
      if (tok != expectedToken) throw new InvalidMetadataException(ExceptionStrings.MalformedSignature);
    }
    private Method GetConstructorDefOrRef(int codedIndex, out TypeNodeList varArgTypes) {
      varArgTypes = null;
      switch(codedIndex & 0x7){
        case 0x02 : return this.GetMethodFromDef(codedIndex >> 3); 
        case 0x03 : return (Method)this.GetMemberFromRef(codedIndex >> 3, out varArgTypes);
      }
      throw new InvalidMetadataException(ExceptionStrings.BadCustomAttributeTypeEncodedToken);
    }
    private void GetResources(Module/*!*/ module) {
      ManifestResourceRow[] manifestResourceTable = this.tables.ManifestResourceTable;
      int n = manifestResourceTable.Length; 
      ResourceList resources = new ResourceList(n);
      for (int i = 0; i < n; i++){
        ManifestResourceRow mrr = manifestResourceTable[i];
        Resource r = new Resource();
        r.Name = this.tables.GetString(mrr.Name);
        r.IsPublic = (mrr.Flags&7) == 1;
        int impl = mrr.Implementation;
        if (impl != 0){
          switch(impl & 0x3){
            case 0x0: 
              string modName = this.tables.GetString(this.tables.FileTable[(impl >> 2)-1].Name);
              if ((this.tables.FileTable[(impl >> 2)-1].Flags & (int)FileFlags.ContainsNoMetaData) != 0){
                r.DefiningModule = new Module();
                r.DefiningModule.Directory = module.Directory;
                r.DefiningModule.Location = Path.Combine(module.Directory,modName);
                r.DefiningModule.Name = modName;
                r.DefiningModule.Kind = ModuleKindFlags.ManifestResourceFile;
                r.DefiningModule.ContainingAssembly = module.ContainingAssembly;
                r.DefiningModule.HashValue = this.tables.GetBlob(this.tables.FileTable[(impl >> 2) - 1].HashValue);
              } else {
                string modLocation = modName;
                r.DefiningModule = GetNestedModule(module, modName, ref modLocation);
              }
              break;
            case 0x1: 
              r.DefiningModule = this.tables.AssemblyRefTable[(impl >> 2)-1].AssemblyReference.Assembly;
              break;
          }
        }else{
          r.DefiningModule = module;
          r.Data = this.tables.GetResourceData(mrr.Offset);
        }
        resources.Add(r);
      }
      module.Resources = resources;
      module.Win32Resources = this.tables.ReadWin32Resources();
    }
    private SecurityAttribute GetSecurityAttribute(int i){
      DeclSecurityRow dsr = this.tables.DeclSecurityTable[i];
      SecurityAttribute attr = new SecurityAttribute();
      attr.Action = (System.Security.Permissions.SecurityAction)dsr.Action;
      if (this.module.MetadataFormatMajorVersion > 1 || this.module.MetadataFormatMinorVersion > 0){
        attr.PermissionAttributes = this.GetPermissionAttributes(dsr.PermissionSet, attr.Action);
        if (attr.PermissionAttributes != null) return attr;
      }
      attr.SerializedPermissions = (string)this.tables.GetBlobString(dsr.PermissionSet);
      return attr;
    }
    private AttributeList GetPermissionAttributes(int blobIndex, System.Security.Permissions.SecurityAction action){
      AttributeList result = new AttributeList();
      int blobLength;
      MemoryCursor sigReader = this.tables.GetBlobCursor(blobIndex, out blobLength);
      if (blobLength == 0) return null;
      byte header = sigReader.ReadByte();
      if (header != (byte)'*'){
        if (header == (byte)'<') return null;
        if (header == (byte)'.') return this.GetPermissionAttributes2(blobIndex, action);
        HandleError(this.module, ExceptionStrings.BadSecurityPermissionSetBlob);
        return null;
      }
      sigReader.ReadInt32(); //Skip over the token for the attribute target
      sigReader.ReadInt32(); //Skip over the security action
      int numAttrs = sigReader.ReadInt32();
      for (int i = 0; i < numAttrs; i++)
        result.Add(this.GetPermissionAttribute(sigReader));
      return result;
    }
    private AttributeNode GetPermissionAttribute(MemoryCursor/*!*/ sigReader) {
      sigReader.ReadInt32(); //Skip over index
      int typeNameLength = sigReader.ReadInt32();
      sigReader.ReadUTF8(typeNameLength); //Skip over type name
      int constructorToken = sigReader.ReadInt32();
      sigReader.ReadInt32(); //Skip over attribute type token
      sigReader.ReadInt32(); //Skip over assembly ref token
      int caBlobLength = sigReader.ReadInt32();
      sigReader.ReadInt32(); //Skip over the number of parameters in the CA blob
      TypeNodeList varArgTypes; //Ignored because vararg constructors are not allowed in Custom Attributes
      Method cons = this.GetConstructorDefOrRef(constructorToken, out varArgTypes);
      if (cons == null) cons = new Method();
      return this.GetCustomAttribute(cons, sigReader, caBlobLength);
    }
    private AttributeList GetPermissionAttributes2(int blobIndex, System.Security.Permissions.SecurityAction action){
      AttributeList result = new AttributeList();
      int blobLength;
      MemoryCursor sigReader = this.tables.GetBlobCursor(blobIndex, out blobLength);
      if (blobLength == 0) return null;
      byte header = sigReader.ReadByte();
      if (header != (byte)'.'){
        HandleError(this.module, ExceptionStrings.BadSecurityPermissionSetBlob);
        return null;
      }
      int numAttrs = sigReader.ReadCompressedInt();
      for (int i = 0; i < numAttrs; i++)
        result.Add(this.GetPermissionAttribute2(sigReader, action));
      return result;
    }
    private AttributeNode GetPermissionAttribute2(MemoryCursor/*!*/ sigReader, System.Security.Permissions.SecurityAction action) {
      int typeNameLength = sigReader.ReadCompressedInt();
      string serializedTypeName = sigReader.ReadUTF8(typeNameLength);
      TypeNode attrType = null;
      try{
        attrType = this.GetTypeFromSerializedName(serializedTypeName);
      }catch(InvalidMetadataException){}
      if (attrType == null){
        HandleError(this.module, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.CouldNotResolveType,serializedTypeName));
        return null;
      }
      InstanceInitializer cons = attrType.GetConstructor(CoreSystemTypes.SecurityAction);
      if (cons == null){
        HandleError(this.module, String.Format(CultureInfo.CurrentCulture, 
        ExceptionStrings.SecurityAttributeTypeDoesNotHaveADefaultConstructor, serializedTypeName));
        return null;
      }
      sigReader.ReadCompressedInt(); //caBlobLength
      int numProps = sigReader.ReadCompressedInt(); //Skip over the number of properties in the CA blob
      ExpressionList arguments = new ExpressionList(numProps+1);
      arguments.Add(new Literal(action, CoreSystemTypes.SecurityAction));
      this.GetCustomAttributeNamedArguments(arguments, (ushort)numProps, sigReader);
      return new AttributeNode(new MemberBinding(null, cons), arguments);
    }
    private static void HandleError(Module mod, string errorMessage){
#if !FxCop
      if (mod != null && (mod.ContainingAssembly == null || (mod.ContainingAssembly.Flags & AssemblyFlags.ContainsForeignTypes) == 0)){
        if (mod.MetadataImportErrors == null) mod.MetadataImportErrors = new ArrayList();
        mod.MetadataImportErrors.Add(new InvalidMetadataException(errorMessage));
      }
#else
      throw new InvalidMetadataException(String.Format(CultureInfo.CurrentCulture, ExceptionStrings.ModuleError, mod.Name, errorMessage));
#endif
    }
    private AttributeNode GetCustomAttribute(int i){
      CustomAttributeRow ca = this.tables.CustomAttributeTable[i];
      TypeNodeList varArgTypes; //Ignored because vararg constructors are not allowed in Custom Attributes
      Method cons = this.GetConstructorDefOrRef(ca.Constructor, out varArgTypes);
      if (cons == null) cons = new Method();
      int blobLength;
      MemoryCursor sigReader = this.tables.GetBlobCursor(ca.Value, out blobLength);
      return this.GetCustomAttribute(cons, sigReader, blobLength);
    }
    private AttributeNode GetCustomAttribute(Method/*!*/ cons, MemoryCursor/*!*/ sigReader, int blobLength) {
      AttributeNode attr = new AttributeNode();
      attr.Constructor = new MemberBinding(null, cons);
      int n = cons.Parameters == null ? 0 : cons.Parameters.Count;
      ExpressionList arguments = attr.Expressions = new ExpressionList(n);
      int posAtBlobStart = sigReader.Position;
      sigReader.ReadUInt16(); //Prolog
      for (int j = 0; j < n; j++){
        TypeNode t = TypeNode.StripModifiers(cons.Parameters[j].Type);
        if (t == null) continue;
        TypeNode/*!*/ pt = t;
        object val = null;
        try{
          val = this.GetCustomAttributeLiteralValue(sigReader, ref pt);
#if !FxCop        
        }catch (Exception e){ 
          if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
          this.module.MetadataImportErrors.Add(e);
        }
#else
        }finally{}
#endif
        Literal lit = val as Literal;
        if (lit == null) lit = new Literal(val, pt);
        arguments.Add(lit);
      }
      if (sigReader.Position+1 < posAtBlobStart + blobLength){
        ushort numNamed = sigReader.ReadUInt16();
        this.GetCustomAttributeNamedArguments(arguments, numNamed, sigReader);
      }
      return attr;
    }
    private void GetCustomAttributeNamedArguments(ExpressionList/*!*/ arguments, ushort numNamed, MemoryCursor/*!*/ sigReader) {
      for (int j = 0; j < numNamed; j++){
        int nameTag = sigReader.ReadByte();
        bool mustBox = sigReader.Byte(0) == (byte)ElementType.BoxedEnum;
        TypeNode/*!*/ vType = this.ParseTypeSignature(sigReader);
        Identifier id = sigReader.ReadIdentifierFromSerString();
        object val = this.GetCustomAttributeLiteralValue(sigReader, ref vType);
        Literal lit = val as Literal;
        if (lit == null) lit = new Literal(val, vType);
        NamedArgument narg = new NamedArgument(id, lit);
        narg.Type = vType;
        narg.IsCustomAttributeProperty = nameTag == 0x54;
        narg.ValueIsBoxed = mustBox;
        arguments.Add(narg);
      }
    }
    private object GetCustomAttributeLiteralValue(MemoryCursor/*!*/ sigReader, TypeNode/*!*/ type) {
      TypeNode/*!*/ t = type;
      object result = this.GetCustomAttributeLiteralValue(sigReader, ref t);
      EnumNode enumType = t as EnumNode;
      if (enumType != null && type == CoreSystemTypes.Object) result = new Literal(result, enumType);
      else if (type == CoreSystemTypes.Object && t != CoreSystemTypes.Object) {
        Literal lit = result as Literal;
        if (lit == null) result = new Literal(result, t);
      }
      return result;
    }
    private object GetCustomAttributeLiteralValue(MemoryCursor/*!*/ sigReader, ref TypeNode/*!*/ type) {
      if (type == null) return sigReader.ReadInt32();
      switch(type.typeCode){
        case ElementType.Boolean: return sigReader.ReadBoolean();
        case ElementType.Char: return sigReader.ReadChar();
        case ElementType.Double: return sigReader.ReadDouble();
        case ElementType.Single: return sigReader.ReadSingle(); 
        case ElementType.Int16: return sigReader.ReadInt16();
        case ElementType.Int32: return sigReader.ReadInt32();
        case ElementType.Int64: return sigReader.ReadInt64();
        case ElementType.Int8: return sigReader.ReadSByte();
        case ElementType.UInt16: return sigReader.ReadUInt16();
        case ElementType.UInt32: return sigReader.ReadUInt32();
        case ElementType.UInt64: return sigReader.ReadUInt64();
        case ElementType.UInt8: return sigReader.ReadByte();
        case ElementType.String: return ReadSerString(sigReader);
        case ElementType.ValueType:
          EnumNode etype = GetCustomAttributeEnumNode(ref type);
          var enumVal = this.GetCustomAttributeLiteralValue(sigReader, etype.UnderlyingType);
#if !MinimalReader
          if (this.module.ContainingAssembly != null && (this.module.ContainingAssembly.Flags & AssemblyFlags.ContainsForeignTypes) != 0) {
            if (etype == SystemTypes.AttributeTargets) {
              switch ((int)enumVal) {
                case 0x00000001: enumVal = 0x00001000; break;
                case 0x00000002: enumVal = 0x00000010; break;
                case 0x00000004: enumVal = 0x00000200; break;
                case 0x00000008: enumVal = 0x00000100; break;
                case 0x00000010: enumVal = 0x00000400; break;
                case 0x00000020: enumVal = 0x00000000; break;
                case 0x00000040: enumVal = 0x00000040; break;
                case 0x00000080: enumVal = 0x00000800; break;
                case 0x00000100: enumVal = 0x00000080; break;
                case 0x00000200: enumVal = 0x00000004; break;
                case 0x00000400: enumVal = 0x00000008; break;
                case 0x00000800: enumVal = 0x00000000; break;
                case -1: enumVal = 0x00007FFF; break;
              }
            }
          }
#endif
          return enumVal;
        case ElementType.Class: return this.GetTypeFromSerializedName(ReadSerString(sigReader));
        case ElementType.SzArray:
          int numElems = sigReader.ReadInt32();
          TypeNode elemType = ((ArrayType)type).ElementType;
          return this.GetCustomAttributeLiteralArray(sigReader, numElems, elemType);
        case ElementType.Object:{
          type = this.ParseTypeSignature(sigReader);
          return this.GetCustomAttributeLiteralValue(sigReader, ref type);
        }
      }
      throw new InvalidMetadataException(ExceptionStrings.UnexpectedTypeInCustomAttribute);
    }
    private static EnumNode/*!*/ GetCustomAttributeEnumNode(ref TypeNode/*!*/ type) {
      EnumNode etype = ((TypeNode)type) as EnumNode;
      if (etype == null || etype.UnderlyingType == null){
        //Happens when type is declared in a assembly that has not been resolved. In that case only the type name
        //and the fact that it is a value type is known. There is no completely safe recovery from it, but at this point we
        //can fake up an enum with Int32 as underlying type. This works in most situations.
        etype = new EnumNode();
        etype.Name = type.Name;
        etype.Namespace = type.Namespace;
        etype.DeclaringModule = type.DeclaringModule;
        etype.UnderlyingType = CoreSystemTypes.Int32;
        type = etype;
      }
      return etype;
    }
    private Array GetCustomAttributeLiteralArray(MemoryCursor/*!*/ sigReader, int numElems, TypeNode/*!*/ elemType) {
      Array array = this.ConstructCustomAttributeLiteralArray(numElems, elemType);
      for (int i = 0; i < numElems; i++) {
        object elem = this.GetCustomAttributeLiteralValue(sigReader, elemType);
        array.SetValue(elem, i);
      }
      return array;
    }
    private Array ConstructCustomAttributeLiteralArray(int numElems, TypeNode/*!*/ elemType) {
      if (numElems == -1) return null;
      if (numElems < 0) throw new InvalidMetadataException(ExceptionStrings.UnexpectedTypeInCustomAttribute);
      switch(elemType.typeCode){
        case ElementType.Boolean: return new Boolean[numElems];
        case ElementType.Char: return new Char[numElems];
        case ElementType.Double: return new Double[numElems];
        case ElementType.Single: return new Single[numElems]; 
        case ElementType.Int16: return new Int16[numElems];
        case ElementType.Int32: return new Int32[numElems];
        case ElementType.Int64: return new Int64[numElems];
        case ElementType.Int8: return new SByte[numElems];
        case ElementType.UInt16: return new UInt16[numElems];
        case ElementType.UInt32: return new UInt32[numElems];
        case ElementType.UInt64: return new UInt64[numElems];
        case ElementType.UInt8: return new Byte[numElems];
        case ElementType.String: return new String[numElems];
        // Only enum value types are legal in attribute instances as stated in section 17.1.3 of the C# 1.0 spec
        case ElementType.ValueType:
          TypeNode/*!*/ elType = elemType;
          EnumNode eType = GetCustomAttributeEnumNode(ref elType);
          return this.ConstructCustomAttributeLiteralArray(numElems, eType.UnderlyingType);
        // This needs to be a TypeNode since GetCustomAttributeLiteralValue will return a Struct if the Type is a value type
        case ElementType.Class: return new TypeNode[numElems];
        // REVIEW: Is this the right exception? Is this the right exception string?
        // Multi-dimensional arrays are not legal in attribute instances according section 17.1.3 of the C# 1.0 spec
        case ElementType.SzArray: throw new InvalidMetadataException(ExceptionStrings.BadCustomAttributeTypeEncodedToken);
        case ElementType.Object: return new Object[numElems];
      }
      throw new InvalidMetadataException(ExceptionStrings.UnexpectedTypeInCustomAttribute);
    }
    private TypeNode GetTypeFromSerializedName(string serializedName)
    {
      if (serializedName == null) return null;
      SerializedTypeName name;
      if (!SerializedTypeName.TryParse(serializedName, out name))
        throw new InvalidMetadataException(ExceptionStrings.BadSerializedTypeName);
      return this.GetTypeFromTypeName(name);
    }
    private TypeNode GetTypeFromTypeName(SerializedTypeName typeName)
    {
      string firstName = typeName.Names.Count > 0 ? typeName.Names[0] : string.Empty;
      int lastDot = firstName.LastIndexOf('.');
      string ns, name;
      if (lastDot < 0) {
        ns = string.Empty;
        name = firstName;
      } else {
        ns = firstName.Substring(0, lastDot);
        name = firstName.Substring(lastDot + 1);
      }
      Module mod;
      TypeNode type = this.LookupType(ns, name, typeName.Assembly, out mod);
      if (type == null)
        type = this.GetDummyTypeNode(Identifier.For(ns), Identifier.For(name), mod, null, false);
      if (typeName.Names.Count > 1)
        for (int i = 1; i < typeName.Names.Count; i++) {
          TypeNode t = type.GetNestedType(Identifier.For(typeName.Names[i]));
          if (t == null)
            t = this.GetDummyTypeNode(Identifier.Empty, Identifier.For(typeName.Names[i]), type.DeclaringModule, type, false);
          type = t;
        }
      if (typeName.GenericArguments.Count > 0) {
        TypeNodeList arguments = new TypeNodeList();
        foreach (SerializedTypeName genArg in typeName.GenericArguments)
          arguments.Add(this.GetTypeFromTypeName(genArg));
        type = type.GetGenericTemplateInstance(this.module, arguments);
      }
      return typeName.ApplySignature(type);
    }
    private TypeNode LookupType(string /*!*/ nameSpace, string /*!*/ name, string assemblyName, out Module module) {
      Identifier namespaceId = Identifier.For(nameSpace);
      Identifier nameId = Identifier.For(name);
      module = this.module;
      //^ assume module != null;
      if (string.IsNullOrEmpty(assemblyName)) {
        TypeNode t = module.GetType(namespaceId, nameId);
        if (t != null) return t;
        module = CoreSystemTypes.SystemAssembly;
        return CoreSystemTypes.SystemAssembly.GetType(namespaceId, nameId);
      }
      //See if the type is in one of the assemblies explcitly referenced by the current module
      AssemblyReferenceList arefs = module.AssemblyReferences;
      for (int i = 0, n = arefs == null ? 0 : arefs.Count; i < n; i++) {
        AssemblyReference aref = arefs[i];
        if (aref != null && aref.StrongName == assemblyName && aref.Assembly != null) {
          module = aref.Assembly;
          return aref.Assembly.GetType(namespaceId, nameId);
        }
      }
      //Construct an assembly reference and probe for it
      AssemblyReference aRef = new AssemblyReference(assemblyName);
      AssemblyNode referringAssembly = this.module as AssemblyNode;
      if (referringAssembly != null && (referringAssembly.Flags & AssemblyFlags.Retargetable) != 0)
        aRef.Flags |= AssemblyFlags.Retargetable;
      AssemblyNode aNode = this.GetAssemblyFromReference(aRef);
      if (aNode != null) {
        module = aNode;
        TypeNode result = aNode.GetType(namespaceId, nameId);
        return result;
      }
      return null;
    }
    private void GetCustomAttributesFor(Module/*!*/ module) {
      try{
        if (this.tables.entryPointToken != 0)
          module.EntryPoint = (Method)this.GetMemberFromToken(this.tables.entryPointToken);
        else
          module.EntryPoint = Module.NoSuchMethod;
        if (module.NodeType == NodeType.Module) {
          module.Attributes = this.GetCustomAttributesNonNullFor((1 << 5) | 7);
          return;
        }
        AssemblyNode assembly = (AssemblyNode)module;
        assembly.SecurityAttributes = this.GetSecurityAttributesFor((1 << 2)|2);
        assembly.Attributes = this.GetCustomAttributesNonNullFor((1 << 5) | 14);
        assembly.ModuleAttributes = this.GetCustomAttributesNonNullFor((1 << 5) | 7);
#if !FxCop
      }catch(Exception e){
        if (this.module == null) return;
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
        module.Attributes = new AttributeList(0);
      }
#else
      }finally{}
#endif
    }
    private AttributeList/*!*/ GetCustomAttributesNonNullFor(int parentIndex) {
      var result = GetCustomAttributesFor(parentIndex);
      if (result != null) return result;
      return new AttributeList(0);
    }
    private AttributeList GetCustomAttributesFor(int parentIndex) {
      CustomAttributeRow[] customAttributes = this.tables.CustomAttributeTable;
      AttributeList attributes = null;
      try{
        int i = 0, n = customAttributes.Length, j = n-1;
        if (n == 0) return null;
        bool sorted = (this.sortedTablesMask >> (int)TableIndices.CustomAttribute) % 2 == 1;
        if (sorted){
          while (i < j){
            int k = (i+j) / 2;
            if (customAttributes[k].Parent < parentIndex)
              i = k+1;
            else
              j = k;
          }
          while (i > 0 && customAttributes[i-1].Parent == parentIndex) i--;
        }
        int count = 0;
        for (int l = i; l < n; l++)
          if (customAttributes[l].Parent == parentIndex)
            count++;
          else if (sorted)
            break;
        if (count > 0) {
          attributes = new AttributeList(count);
        }
        for (; i < n; i++)
          if (customAttributes[i].Parent == parentIndex)
            attributes.Add(this.GetCustomAttribute(i));
          else if (sorted)
            break;
#if !FxCop
      }catch(Exception e){
        if (this.module == null) return attributes;
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
      }
#else
      }finally{}
#endif
      return attributes;
    }
    private SecurityAttributeList GetSecurityAttributesFor(int parentIndex){
      DeclSecurityRow[] securityAttributes = this.tables.DeclSecurityTable;
      SecurityAttributeList attributes = new SecurityAttributeList();
      try{
        int i = 0, n = securityAttributes.Length, j = n-1;
        if (n == 0) return attributes;
        bool sorted = (this.sortedTablesMask >> (int)TableIndices.DeclSecurity) % 2 == 1;
        if (sorted){
          while (i < j){
            int k = (i+j) / 2;
            if (securityAttributes[k].Parent < parentIndex)
              i = k+1;
            else
              j = k;
          }
          while (i > 0 && securityAttributes[i-1].Parent == parentIndex) i--;
        }
        for (; i < n; i++)
          if (securityAttributes[i].Parent == parentIndex)
            attributes.Add(this.GetSecurityAttribute(i));
          else if (sorted)
            break;
#if !FxCop
      }catch(Exception e){
        if (this.module == null) return attributes;
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
      }
#else
      }finally{}
#endif
      return attributes;
    }
    private void GetTypeParameterConstraints(int parentIndex, TypeNodeList parameters){
      if (parameters == null) return;
      GenericParamRow[] genericParameters = this.tables.GenericParamTable;
      int i = 0, n = genericParameters.Length, j = n-1;
      bool sorted = (this.sortedTablesMask >> (int)TableIndices.GenericParam) % 2 == 1;
      if (sorted){
        while (i < j){
          int k = (i+j) / 2;
          if (genericParameters[k].Owner < parentIndex)
            i = k+1;
          else
            j = k;
        }
        while (i > 0 && genericParameters[i-1].Owner == parentIndex) i--;
      }
      for (int k = 0; i < n && k < parameters.Count; i++, k++)
        if (genericParameters[i].Owner == parentIndex) {
          TypeNode gp = parameters[k];
          this.GetGenericParameterConstraints(i, ref gp);
          parameters[k] = gp;
        } else if (sorted)
          break;
    }
    private TypeNodeList GetTypeParametersFor(int parentIndex, Member parent){
      GenericParamRow[] genericParameters = this.tables.GenericParamTable;
      TypeNodeList types = new TypeNodeList();
      TypeNodeList savedTypes = this.currentTypeParameters;
      this.currentTypeParameters = types;
      try
      {
        int i = 0, n = genericParameters.Length, j = n-1;
        bool sorted = (this.sortedTablesMask >> (int)TableIndices.GenericParam) % 2 == 1;
        if (sorted){
          while (i < j){
            int k = (i+j) / 2;
            if (genericParameters[k].Owner < parentIndex)
              i = k+1;
            else
              j = k;
          }
          while (i > 0 && genericParameters[i-1].Owner == parentIndex) i--;
        }
        for (int index = 0; i < n; i++, index++)
          if (genericParameters[i].Owner == parentIndex)
            types.Add(this.GetGenericParameter(i, index, parent));
          else if (sorted)
            break;
        if (types.Count == 0) return null;
          return types;
      }
      finally
      {
        this.currentTypeParameters = savedTypes;
      }
    }
    private TypeNode GetGenericParameter(int index, int parameterListIndex, Member parent){
      GenericParamRow[] genericParameters = this.tables.GenericParamTable;
      GenericParamRow gpr = genericParameters[index++];
      string name = this.tables.GetString(gpr.Name);
      GenericParamConstraintRow[] genericParameterConstraints = this.tables.GenericParamConstraintTable;
      bool isClass = false;
      int i = 0, n = genericParameterConstraints.Length, j = n-1;
      bool sorted = (this.sortedTablesMask >> (int)TableIndices.GenericParamConstraint) % 2 == 1;
      if (sorted){
        while (i < j){
          int k = (i+j) / 2;
          if (genericParameterConstraints[k].Param < index)
            i = k+1;
          else
            j = k;
        }
        while (i > 0 && genericParameterConstraints[i-1].Param == index) i--;
      }
      for (; i < n && !isClass; i++){
        if (genericParameterConstraints[i].Param == index){
          isClass = this.TypeDefOrRefOrSpecIsClass(genericParameterConstraints[i].Constraint);
        }else if (sorted)
          break;
      }
      if (isClass){
        ClassParameter cp = parent is Method ? new MethodClassParameter() : new ClassParameter();
        cp.DeclaringMember = parent;
        cp.ParameterListIndex = parameterListIndex;
        cp.Name = Identifier.For(name);
        cp.DeclaringModule = this.module;
        cp.TypeParameterFlags = (TypeParameterFlags)gpr.Flags;
        cp.ProvideTypeAttributes = this.GetTypeParameterAttributes;
        cp.ProviderHandle = index;
        return cp;
      }
      TypeParameter tp = parent is Method ? new MethodTypeParameter() : new TypeParameter();
      tp.DeclaringMember = parent;
      tp.ParameterListIndex = parameterListIndex;
      tp.Name = Identifier.For(name);
      tp.DeclaringModule = this.module;
      tp.TypeParameterFlags = (TypeParameterFlags)gpr.Flags;
      tp.ProvideTypeAttributes = this.GetTypeParameterAttributes;
      tp.ProviderHandle = index;
      return tp;
    }
    private void GetGenericParameterConstraints(int index, ref TypeNode/*!*/ parameter) {
      Debug.Assert(parameter != null);
      index++;
      GenericParamConstraintRow[] genericParameterConstraints = this.tables.GenericParamConstraintTable;
      TypeNodeList constraints = new TypeNodeList();
      Class baseClass = null;
      InterfaceList interfaces = new InterfaceList();
      int i = 0, n = genericParameterConstraints.Length, j = n-1;
      bool sorted = (this.sortedTablesMask >> (int)TableIndices.GenericParamConstraint) % 2 == 1;
      if (sorted){
        while (i < j){
          int k = (i+j) / 2;
          if (genericParameterConstraints[k].Param < index)
            i = k+1;
          else
            j = k;
        }
        while (i > 0 && genericParameterConstraints[i-1].Param == index) i--;
      }
      for (; i < n; i++){
        if (genericParameterConstraints[i].Param == index){
          TypeNode t = this.DecodeAndGetTypeDefOrRefOrSpec(genericParameterConstraints[i].Constraint);
          Class c = t as Class;
          if (c != null)
          {
            if (baseClass == null)
            {
              baseClass = c;
            }
            else
            {
              // CCI1 has a broken view of type parameter constraints. Type parameters are not known to be class constrained or multiple ones can be class constrained.
            }
          }
          else if (t is Interface)
            interfaces.Add((Interface)t);
          constraints.Add(t);
        }else if (sorted)
          break;
      }
      ClassParameter cp = parameter as ClassParameter;
      if (cp == null && baseClass != null) {
        cp = ((ITypeParameter)parameter).DeclaringMember is Method ? new MethodClassParameter() : new ClassParameter();        
        cp.Name = parameter.Name;
        cp.DeclaringMember = ((ITypeParameter)parameter).DeclaringMember;
        cp.ParameterListIndex = ((ITypeParameter)parameter).ParameterListIndex;
        cp.DeclaringModule = this.module;
        cp.TypeParameterFlags = ((ITypeParameter)parameter).TypeParameterFlags;
        cp.ProvideTypeAttributes = this.GetTypeParameterAttributes;
        cp.ProviderHandle = index;
        parameter = cp;
      }
      if (cp != null)
        cp.structuralElementTypes = constraints;
      else
        ((TypeParameter)parameter).structuralElementTypes = constraints;
      if (baseClass != null && cp != null) cp.BaseClass = baseClass;
      parameter.Interfaces = interfaces;
    }
    internal static Block/*!*/ GetOrCreateBlock(TrivialHashtable/*!*/ blockMap, int address) {
      Block block = (Block)blockMap[address+1];
      if (block == null){
        blockMap[address+1] = block = new Block(new StatementList());
#if !FxCop && !CodeContracts
        var sctx = block.SourceContext;
        sctx.StartPos = address;
        block.SourceContext = sctx;
#else
        block.ILOffset = address;
#endif
#if ILOFFSETS
        block.ILOffset = address;
#endif
      }
      return block;
    }
    internal Field GetFieldFromDef(int i){
      return this.GetFieldFromDef(i, null);
    }
    internal Field GetFieldFromDef(int i, TypeNode declaringType){
      FieldRow[] fieldDefs = this.tables.FieldTable;
      FieldRow fld = fieldDefs[i-1];
      if (fld.Field != null) return fld.Field;
      Field field = new Field();
      fieldDefs[i-1].Field = field;
      field.Attributes = this.GetCustomAttributesFor((i << 5)|1);
      field.Flags = (FieldFlags)fld.Flags;
      field.Name = tables.GetIdentifier(fld.Name);
      if ((field.Flags & FieldFlags.RTSpecialName) != 0 && field.Name.UniqueIdKey == StandardIds._Deleted.UniqueIdKey) return null;
      tables.GetSignatureLength(fld.Signature); //sigLength
      MemoryCursor sigReader = this.tables.GetNewCursor();
      GetAndCheckSignatureToken(6, sigReader);
      field.Type = this.ParseTypeSignature(sigReader);
      RequiredModifier reqMod = field.Type as RequiredModifier;
      if (reqMod != null && reqMod.Modifier == CoreSystemTypes.IsVolatile) {
        field.IsVolatile = true;
        field.Type = reqMod.ModifiedType;
      }
      if ((field.Flags & FieldFlags.HasDefault) != 0) 
        field.DefaultValue = this.GetLiteral(i << 2, field.Type);
      if ((field.Flags & FieldFlags.HasFieldMarshal) != 0)
        field.MarshallingInformation = this.GetMarshallingInformation((i << 1)|0);
      if ((field.Flags & FieldFlags.HasFieldRVA) != 0)
        field.InitialData = this.GetInitialData(i, field.Type, out field.section);
      if (declaringType == null){
        TypeDefRow[] typeDefs = this.tables.TypeDefTable;
        int indx = i;
        FieldPtrRow[] fieldPtrs = this.tables.FieldPtrTable;
        int n = fieldPtrs.Length;
        for (int j = 0; j < n; j++){
          if (fieldPtrs[j].Field == i){
            indx = j+1; break;
          }
        }
        n = typeDefs.Length;
        for (int j = n-1; j >= 0; j--){ //TODO: binary search
          TypeDefRow tdr = typeDefs[j];
          if (tdr.FieldList <= indx){
            declaringType = this.GetTypeFromDef(j+1);
            break;
          }
        }
      }
      field.DeclaringType = declaringType;
      if (declaringType != null && (declaringType.Flags & TypeFlags.ExplicitLayout) != 0){
        FieldLayoutRow[] fieldLayouts = this.tables.FieldLayoutTable;
        int n = fieldLayouts.Length;
        for (int j = n-1; j >= 0; j--){ //TODO: binary search
          FieldLayoutRow flr = fieldLayouts[j];
          if (flr.Field == i){
            field.Offset = flr.Offset;
            break;
          }
        }
      }
      return field;
    }
    private byte[] GetInitialData(int fieldIndex, TypeNode fieldType, out PESection targetSection) {
      targetSection = PESection.Text;
      FieldRvaRow[] fieldRvaTable = this.tables.FieldRvaTable;
      bool sorted = (this.sortedTablesMask >> (int)TableIndices.FieldRva) % 2 == 1;
      int i = 0, n = fieldRvaTable.Length, j = n-1;
      if (n == 0) return null;
      if (sorted){
        while (i < j){
          int k = (i+j) / 2;
          if (fieldRvaTable[k].Field < fieldIndex)
            i = k+1;
          else
            j = k;
        }
      }else
        for (; i < j; i++)
          if (fieldRvaTable[i].Field == fieldIndex) break;
      FieldRvaRow frr = fieldRvaTable[i];
      if (frr.Field != fieldIndex) return null;
      Field fld = this.tables.FieldTable[fieldIndex-1].Field;
      if (fld != null) fld.Offset = frr.RVA;
      fieldType = TypeNode.StripModifiers(fieldType);
      EnumNode enumType = fieldType as EnumNode;
      if (enumType != null) fieldType = TypeNode.StripModifiers(enumType.UnderlyingType);
      if (fieldType == null) { Debug.Fail(""); return null; }
      int size = fieldType.ClassSize;
      if (size <= 0){
        switch (fieldType.typeCode){
          case ElementType.Boolean: size = 1; break;
          case ElementType.Char: size = 2; break;
          case ElementType.Double: size = 8; break;
          case ElementType.Int16: size = 2; break;
          case ElementType.Int32: size = 4; break;
          case ElementType.Int64: size = 8; break;
          case ElementType.Int8: size = 1; break;
          case ElementType.Single: size = 4; break;
          case ElementType.UInt16: size = 2; break;
          case ElementType.UInt32: size = 4; break;
          case ElementType.UInt64: size = 8; break;
          case ElementType.UInt8: size = 1; break;
          default:
            if (fieldType is Pointer || fieldType is FunctionPointer){
              size = 4; break;
            }
            //TODO: this seems wrong
            if (i < n-1)
              size = fieldRvaTable[i+1].RVA - frr.RVA;
            else if (targetSection != PESection.Text)
              size = this.tables.GetOffsetToEndOfSection(frr.RVA);
            break;
        }
      }
      if (size <= 0) return null;
      if (this.tables.NoOffsetFor(frr.RVA) || this.tables.NoOffsetFor(frr.RVA+size-1))
        return null;
      MemoryCursor c = this.tables.GetNewCursor(frr.RVA, out targetSection);
      byte[] result = new byte[size];
      for (i = 0; i < size; i++)
        result[i] = c.ReadByte();
      return result;
    }
    private Literal GetLiteral(int parentCodedIndex, TypeNode/*!*/ type) {
      ConstantRow[] constants = this.tables.ConstantTable;
      //TODO: do a binary search
      for (int i = 0, n = constants.Length; i < n; i++){
        if (constants[i].Parent != parentCodedIndex) continue;
        object value = this.tables.GetValueFromBlob(constants[i].Type, constants[i].Value);
        TypeCode valTypeCode = System.Convert.GetTypeCode(value);
        TypeNode underlyingType = type;
        if (type is EnumNode) underlyingType = ((EnumNode)type).UnderlyingType;
        if (underlyingType.TypeCode != valTypeCode) type = CoreSystemTypes.Object;
        if (type == CoreSystemTypes.Object && value != null){
          switch(valTypeCode){
            case TypeCode.Boolean: type = CoreSystemTypes.Boolean; break;
            case TypeCode.Byte: type = CoreSystemTypes.UInt8; break;
            case TypeCode.Char: type = CoreSystemTypes.Char; break;
            case TypeCode.Double: type = CoreSystemTypes.Double; break;
            case TypeCode.Int16: type = CoreSystemTypes.Int16; break;
            case TypeCode.Int32: type = CoreSystemTypes.Int32; break;
            case TypeCode.Int64: type = CoreSystemTypes.Int64; break;
            case TypeCode.SByte: type = CoreSystemTypes.Int8; break;
            case TypeCode.Single: type = CoreSystemTypes.Single; break;
            case TypeCode.String: type = CoreSystemTypes.String; break;
            case TypeCode.UInt16: type = CoreSystemTypes.UInt16; break;
            case TypeCode.UInt32: type = CoreSystemTypes.UInt32; break;
            case TypeCode.UInt64: type = CoreSystemTypes.UInt64; break;
            case TypeCode.Empty:
            case TypeCode.Object: type = CoreSystemTypes.Type; break;
          }
        }
        return new Literal(value, type);
      }
      throw new InvalidMetadataException(ExceptionStrings.BadConstantParentIndex);
    }
    internal FunctionPointer GetCalliSignature(int ssigToken){
#if !FxCop
      StandAloneSigRow ssr = this.tables.StandAloneSigTable[(ssigToken&0xFFFFFF)-1];      
#else
      int index = (ssigToken & 0xFFFFFF) - 1;
      if (index < 0 || index >= this.tables.StandAloneSigTable.Length)
        return null;

      StandAloneSigRow ssr = this.tables.StandAloneSigTable[index];
#endif
      MemoryCursor sigReader = this.tables.GetBlobCursor(ssr.Signature);
      return this.ParseFunctionPointer(sigReader);
    }
    internal void GetLocals(int localIndex, LocalList/*!*/ locals, System.Collections.Generic.Dictionary<int,LocalInfo>/*!*/ localSourceNames) {
      if (localIndex == 0) return;
      StandAloneSigRow ssr = this.tables.StandAloneSigTable[(localIndex & 0xFFFFFF)-1];
      this.tables.GetSignatureLength(ssr.Signature);
      MemoryCursor sigReader = this.tables.GetNewCursor();
      if (sigReader.ReadByte() != 0x7) throw new InvalidMetadataException(ExceptionStrings.InvalidLocalSignature);
      int count = sigReader.ReadCompressedInt();
      for (int i = 0; i < count; i++){
        LocalInfo localInfo;
        var hasPDBInfo = localSourceNames.TryGetValue(i, out localInfo);
        string lookupName = localInfo.Name;
        bool hasNoPDBName = String.IsNullOrEmpty(lookupName);
#if !FxCop
        
        var name = hasNoPDBName ? "local" + i : lookupName;
#else
        string name = hasNoPDBName ? "local$"+i : lookupName;
#endif
        bool pinned = false;
        TypeNode locType = this.ParseTypeSignature(sigReader, ref pinned);

        Local loc = new Local(Identifier.For(name), locType);
        
        // There is strong relationship between hasNoPDBName and Anonymous.
        // Local is anonymous if Name was generated by the reader and the only
        // case when this happen is hasNoPDBName is true.
        loc.Anonymous = hasNoPDBName;
        loc.Pinned = pinned;
        loc.HasNoPDBInfo = !hasPDBInfo;
        loc.Attributes = localInfo.Attributes;
        locals.Add(loc);
      }
    }
#if !ROTOR && !UseSingularityPDB
    internal void GetLocalSourceNames(ISymUnmanagedScope/*!*/ scope, System.Collections.Generic.Dictionary<int,LocalInfo>/*!*/ localSourceNames) {
      uint numLocals = scope.GetLocalCount();
      IntPtr[] localPtrs = new IntPtr[numLocals];
      scope.GetLocals((uint)localPtrs.Length, out numLocals, localPtrs);

      char[] nameBuffer = new char[100];
      uint nameLen;
      for (int i=0; i<numLocals; i++){
        ISymUnmanagedVariable local =
          (ISymUnmanagedVariable)System.Runtime.InteropServices.Marshal.GetTypedObjectForIUnknown(localPtrs[i], typeof(ISymUnmanagedVariable));
        if (local != null){
          local.GetName((uint)0, out nameLen, null);
          if (nameLen > nameBuffer.Length)
          {
            nameBuffer = new char[nameLen];
          }
          local.GetName((uint)nameBuffer.Length, out nameLen, nameBuffer);
          int localIndex = (int)local.GetAddressField1();
          var localName = new String(nameBuffer, 0, (int)nameLen-1);
          uint attributes = local.GetAttributes();
          localSourceNames[localIndex] = new LocalInfo(localName, attributes);
          System.Runtime.InteropServices.Marshal.ReleaseComObject(local);
        }
        System.Runtime.InteropServices.Marshal.Release(localPtrs[i]);
      }

      IntPtr[] subscopes = new IntPtr[100];
      uint numScopes;
      scope.GetChildren((uint)subscopes.Length, out numScopes, subscopes);
      for (int i=0; i<numScopes; i++){
        ISymUnmanagedScope subscope = 
          (ISymUnmanagedScope)System.Runtime.InteropServices.Marshal.GetTypedObjectForIUnknown(subscopes[i], typeof(ISymUnmanagedScope));
        if (subscope != null){
          this.GetLocalSourceNames(subscope, localSourceNames);
          System.Runtime.InteropServices.Marshal.ReleaseComObject(subscope);
        }
        System.Runtime.InteropServices.Marshal.Release(subscopes[i]);
        //TODO: need to figure out how map these scope to blocks and set HasLocals on those blocks
      }
    }
#endif
    private MarshallingInformation GetMarshallingInformation(int parentCodedIndex){
      FieldMarshalRow[] mtypes = this.tables.FieldMarshalTable;
      bool sorted = (this.sortedTablesMask >> (int)TableIndices.FieldMarshal) % 2 == 1;
      int i = 0, n = mtypes.Length, j = n-1;
      if (n == 0) return null;
      if (sorted){
        while (i < j){
          int k = (i+j) / 2;
          if (mtypes[k].Parent < parentCodedIndex)
            i = k+1;
          else
            j = k;
        }
        while (i > 0 && mtypes[i-1].Parent == parentCodedIndex) i--;
      }else
        for (; i < j; i++)
          if (mtypes[i].Parent == parentCodedIndex) break;
      FieldMarshalRow fmr = mtypes[i];
      if (fmr.Parent != parentCodedIndex) return null;
      MarshallingInformation result = new MarshallingInformation();
      int blobSize = 0;
      MemoryCursor c = this.tables.GetBlobCursor(fmr.NativeType, out blobSize);
      int initialPosition = c.Position;
      result.NativeType = (NativeType)c.ReadByte();
      if (result.NativeType == NativeType.CustomMarshaler){
        c.ReadUInt16(); //Skip over 0
        result.Class = ReadSerString(c);
        result.Cookie = ReadSerString(c);
      }else if (blobSize > 1){
        if (result.NativeType == NativeType.LPArray){
          result.ElementType = (NativeType)c.ReadByte();
          result.ParamIndex = -1;
          int bytesRead = 2;
          if (bytesRead < blobSize){
            int pos = c.Position;
            result.ParamIndex = c.ReadCompressedInt();
            bytesRead += c.Position - pos;
            if (bytesRead < blobSize){
              pos = c.Position;
              result.ElementSize = c.ReadCompressedInt();
              bytesRead += c.Position - pos;
              if (bytesRead < blobSize)
                result.NumberOfElements = c.ReadCompressedInt();
            }
          }
        }else if (result.NativeType == NativeType.SafeArray){
          result.ElementType = (NativeType)c.ReadByte(); //Actually a variant type. TODO: what about VT_VECTOR VT_ARRAY and VT_BYREF?
          if (c.Position < initialPosition+blobSize-1)
            result.Class = ReadSerString(c);
        } else {
          result.Size = c.ReadCompressedInt();
          if (result.NativeType == NativeType.ByValArray) {
            if (c.Position < initialPosition + blobSize) 
              result.ElementType = (NativeType)c.ReadByte();
            else
              result.ElementType = NativeType.NotSpecified;
          }
        }
      }
      return result;
    }
    private void GetMethodBody(Method/*!*/ method, object/*!*/ i, bool asInstructionList) {
      if (asInstructionList){this.GetMethodInstructions(method, i); return;}
      TypeNodeList savedCurrentMethodTypeParameters = this.currentMethodTypeParameters;
      this.currentMethodTypeParameters = method.templateParameters;
      TypeNode savedCurrentType = this.currentType;
      this.currentType = method.DeclaringType;
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      this.currentTypeParameters = this.currentType.TemplateParameters;
      try{
        MethodRow meth = this.tables.MethodTable[((int)i)-1];
        StatementList statements;
        if (meth.RVA != 0 && (((MethodImplFlags)meth.ImplFlags) & MethodImplFlags.ManagedMask) == MethodImplFlags.Managed){
          if (this.getDebugSymbols) this.GetMethodDebugSymbols(method, 0x6000000|(uint)(int)i);
          statements = this.ParseMethodBody(method, (int)i, meth.RVA);
        }else
          statements = new StatementList(0);
        method.Body = new Block(statements);
#if FxCop
        if (statements.Count > 0) {
          SourceContext context = statements[0].SourceContext;
          method.SourceContext = context;
          method.Body.SourceContext = context;
        }
#endif
#if !MinimalReader
        method.Body.HasLocals = true;
#endif
#if !FxCop
      }catch(Exception e){
        if (this.module != null){
          if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
          this.module.MetadataImportErrors.Add(e);
        }
        method.Body = new Block(new StatementList(0));
#endif
      }finally{
        this.currentMethodTypeParameters = savedCurrentMethodTypeParameters;
        this.currentType = savedCurrentType;
        this.currentTypeParameters = savedCurrentTypeParameters;
      }
    }
    private void GetMethodDebugSymbols(Method/*!*/ method, uint methodToken)
      //^ requires this.debugReader != null;
    {
#if UseSingularityPDB
      PdbFunction pdbFunc = this.GetPdbFunction(methodToken);
      if (pdbFunc != null)
        method.RecordSequencePoints(pdbFunc);
#elif !ROTOR
      ISymUnmanagedMethod methodInfo = null;
      try{
        try{
          this.debugReader.GetMethod(methodToken, ref methodInfo);
          this.debugDocuments = new Collections.Generic.Dictionary<IntPtr,UnmanagedDocument>(2); // typically methods have 1 doc
          method.RecordSequencePoints(methodInfo, this.debugDocuments);
        }catch (COMException){
        }catch (InvalidCastException){
        }catch (System.Runtime.InteropServices.InvalidComObjectException){}
      }finally{
        if (methodInfo != null)
          Marshal.ReleaseComObject(methodInfo);
      }
#endif
    }
#if UseSingularityPDB
    internal PdbFunction GetPdbFunction(uint methodToken) {
      PdbFunction[] pdbFunctions = this.pdbFunctions;
      int i = 0, n = pdbFunctions == null ? 0 : pdbFunctions.Length, j = n-1;
      while (i < j) {
        int k = (i+j) / 2;
        if (pdbFunctions[k].token < methodToken)
          i = k+1;
        else
          j = k;
      }
      while (i > 0 && pdbFunctions[i-1].token == methodToken) i--;
      if (0 <= i && i < n && pdbFunctions[i].token == methodToken)
        return pdbFunctions[i];
      return null;
    }
#endif
    private void GetMethodInstructions(Method/*!*/ method, object/*!*/ i) {
      TypeNodeList savedCurrentMethodTypeParameters = this.currentMethodTypeParameters;
      this.currentMethodTypeParameters = method.templateParameters;
      TypeNode savedCurrentType = this.currentType;
      this.currentType = method.DeclaringType;
      try{
        MethodRow meth = this.tables.MethodTable[((int)i)-1];
        if (meth.RVA != 0 && (((MethodImplFlags)meth.ImplFlags) & MethodImplFlags.ManagedMask) == MethodImplFlags.Managed){
          if (this.getDebugSymbols) this.GetMethodDebugSymbols(method, 0x6000000|(uint)(int)i);
          method.Instructions = this.ParseMethodInstructions(method, (int)i, meth.RVA);
        }else
          method.Instructions = new InstructionList(0);
#if !FxCop
      }catch(Exception e){
        if (this.module != null){
          if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
          this.module.MetadataImportErrors.Add(e);
        }
        method.Instructions = new InstructionList(0);
#endif
      }finally{
        this.currentMethodTypeParameters = savedCurrentMethodTypeParameters;
        this.currentType = savedCurrentType;
      }
    }
    internal Method GetMethodDefOrRef(int codedIndex){
      switch(codedIndex & 0x1){
        case 0x00 : return this.GetMethodFromDef(codedIndex >> 1); 
        case 0x01 :
          TypeNodeList varArgTypes;
          return (Method)this.GetMemberFromRef(codedIndex >> 1, out varArgTypes);
      }
      throw new InvalidMetadataException(ExceptionStrings.BadCustomAttributeTypeEncodedToken);
    }
    private Method GetMethodDefOrRef(int codedIndex, int numberOfGenericArguments) {
      switch(codedIndex & 0x1){
        case 0x00 : return this.GetMethodFromDef(codedIndex >> 1); 
        case 0x01 :
          TypeNodeList varArgTypes;
          return (Method)this.GetMemberFromRef(codedIndex >> 1, out varArgTypes, numberOfGenericArguments);
      }
      throw new InvalidMetadataException(ExceptionStrings.BadCustomAttributeTypeEncodedToken);
    }
    internal Method/*!*/ GetMethodFromDef(int index) {
      return this.GetMethodFromDef(index, null);
    }
    internal Method/*!*/ GetMethodFromDef(int index, TypeNode declaringType) {
      TypeNodeList savedCurrentMethodTypeParameters = this.currentMethodTypeParameters;
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      MethodRow[] methodDefs = this.tables.MethodTable;
      MethodRow meth = methodDefs[index-1];
      if (meth.Method != null) return meth.Method;
      if (declaringType == null){
        int indx = index;
        MethodPtrRow[] methodPtrs = this.tables.MethodPtrTable;
        int n = methodPtrs.Length, i = 0, j = n-1;
        bool sorted = (this.sortedTablesMask >> (int)TableIndices.MethodPtr) % 2 == 1;
        if (sorted){
          while (i < j){
            int k = (i+j) / 2;
            if (methodPtrs[k].Method < index)
              i = k+1;
            else
              j = k;
          }
          while (i > 0 && methodPtrs[i-1].Method == index) i--;
        }
        for (; i < n; i++){
          if (methodPtrs[i].Method == index){
            indx = i+1; break;
          }
        }
        TypeDefRow[] typeDefs = this.tables.TypeDefTable;
        n = typeDefs.Length; i=0; j=n-1;
        sorted = (this.sortedTablesMask >> (int)TableIndices.TypeDef) % 2 == 1;
        if (sorted){
          while (i < j){
            int k = (i+j) / 2;
            if (typeDefs[k].MethodList < indx)
              i = k+1;
            else
              j = k;
          }
          j = i;
          while (j < n-1 && typeDefs[j+1].MethodList == indx) j++;
        }
        for (; j >= 0; j--){
          if (typeDefs[j].MethodList <= indx){
            declaringType = this.GetTypeFromDef(j+1);
            break;
          }
        }
      }
      Method.MethodBodyProvider provider = new Method.MethodBodyProvider(this.GetMethodBody);
      Identifier name = tables.GetIdentifier(meth.Name);
      Method method;
      if ((((MethodFlags)meth.Flags) & MethodFlags.SpecialName) != 0 &&
        (((MethodFlags)meth.Flags) & MethodFlags.SpecialName) != 0)
      {
        if (name.Name == ".ctor")
        {
#if ILOFFSETS
          method = methodDefs[index - 1].Method = new InstanceInitializer(provider, index, (int)TableIndices.Method << 24 | index);
#else
          method = methodDefs[index - 1].Method = new InstanceInitializer(provider, index);
#endif
        }
        else if (name.Name == ".cctor")
        {
#if ILOFFSETS
          method = methodDefs[index - 1].Method = new StaticInitializer(provider, index, (int)TableIndices.Method << 24 | index);
#else
          method = methodDefs[index - 1].Method = new StaticInitializer(provider, index);
#endif
        }
        else
        {
#if ILOFFSETS
          method = methodDefs[index - 1].Method = new Method(provider, index, (int)TableIndices.Method << 24 | index);
#else
          method = methodDefs[index - 1].Method = new Method(provider, index);
#endif
        }
      }
      else
      {
#if ILOFFSETS
        method = methodDefs[index - 1].Method = new Method(provider, index, (int)TableIndices.Method << 24 | index);
#else
        method = methodDefs[index - 1].Method = new Method(provider, index);
#endif
      }
      method.ProvideMethodAttributes = new Method.MethodAttributeProvider(this.GetMethodAttributes);
      //method.Attributes = this.GetCustomAttributesFor((index << 5)|0); //TODO: get attributes lazily
      method.Flags = (MethodFlags)meth.Flags;
      method.ImplFlags = (MethodImplFlags)meth.ImplFlags;
      method.Name = name;
      if (declaringType != null) {
        if (declaringType.IsGeneric) {
          if (declaringType.Template != null)
            this.currentTypeParameters = declaringType.ConsolidatedTemplateArguments;
          else
            this.currentTypeParameters = declaringType.ConsolidatedTemplateParameters;
        }
        if (this.module.ProjectTypesContainedInModule && (declaringType.Flags & TypeFlags.IsForeign) != 0) {
          if (method.IsStatic) method.Flags &= ~MethodFlags.NewSlot;
          if (declaringType is DelegateNode) {
            method.Flags &= ~MethodFlags.MethodAccessMask;
            method.Flags |= MethodFlags.Public;
          } else {
            method.ImplFlags |= MethodImplFlags.Runtime | MethodImplFlags.InternalCall;
          }
        }
      }
      
      tables.GetSignatureLength(meth.Signature);
      MemoryCursor sigReader = this.tables.GetNewCursor();
      method.CallingConvention = (CallingConventionFlags)sigReader.ReadByte();
      if (method.IsGeneric = (method.CallingConvention & CallingConventionFlags.Generic) != 0){
        int numTemplateParameters = sigReader.ReadCompressedInt();
        this.currentMethodTypeParameters = new TypeNodeList(numTemplateParameters);
        this.currentMethodTypeParameters = method.TemplateParameters = this.GetTypeParametersFor((index << 1)|1, method);
        this.GetTypeParameterConstraints((index << 1)|1, method.TemplateParameters);
      }
      int numParams = sigReader.ReadCompressedInt();
      method.ReturnType = this.ParseTypeSignature(sigReader);
#if false
      if (declaringType != null && declaringType.IsValueType)
        method.ThisParameter = new This(declaringType.GetReferenceType());
      else
        method.ThisParameter = new This(declaringType);
#endif // materialized on demand
      ParameterList paramList = method.Parameters = new ParameterList(numParams);
      if (numParams > 0){
        int offset = method.IsStatic ? 0 : 1;
        for (int i = 0; i < numParams; i++){
          Parameter param = new Parameter();
          param.ParameterListIndex = i;
          param.ArgumentListIndex = i+offset;
          param.Type = this.ParseTypeSignature(sigReader);
          param.DeclaringMethod = method;
          paramList.Add(param);
        }
        int end = this.tables.ParamTable.Length+1;
        if (index < methodDefs.Length) end = methodDefs[index].ParamList;
        this.AddMoreStuffToParameters(method, paramList, meth.ParamList, end);
        for (int i = 0; i < numParams; i++){
          Parameter param = paramList[i];
          if (param.Name == null) {
            param.Name = Identifier.For("param" + (i));
            param.Flags |= ParameterFlags.ParameterNameMissing;
          }

        }
      }else if (method.ReturnType != CoreSystemTypes.Void){
        //check for custom attributes and marshalling information on return value
        int i = meth.ParamList;
        ParamPtrRow[] parPtrs = this.tables.ParamPtrTable; //TODO: why use ParamPtrTable in the branch and not the one above? Factor this out.
        ParamRow[] pars = this.tables.ParamTable;
        int n = methodDefs.Length;
        int m = pars.Length;
        if (index < n) m = methodDefs[index].ParamList-1;
        if (parPtrs.Length > 0){
          if (pars != null && 0 < i && i <= m){
            int j = parPtrs[i-1].Param;
            ParamRow pr = pars[j-1];
            if (pr.Sequence == 0)
              this.AddMoreStuffToParameters(method, null, j, j+1);
          }
        }else{
          if (pars != null && 0 < i && i <= m){
            ParamRow pr = pars[i-1];
            if (pr.Sequence == 0)
              this.AddMoreStuffToParameters(method, null, i, i+1);
          }
        }
      }
#if ExtendedRuntime
      for (int k = 0, al = method.ReturnAttributes == null ? 0 : method.ReturnAttributes.Count; k < al; k++) {
        if (method.ReturnAttributes[k].Type == ExtendedRuntimeTypes.NotNullAttribute) {
          method.ReturnType = OptionalModifier.For(ExtendedRuntimeTypes.NonNullType, method.ReturnType);
          // Someone putting an attribute directly on the "real" method is still a
          // kind of out-of-band contract.
          // This marking is the way to signal that any override or implementing method being compiled
          // should not have its non-null annotations persisted as optional modifiers.
          method.HasOutOfBandContract = true;
        } else  if (method.ReturnAttributes[k].Type == ExtendedRuntimeTypes.NotNullArrayElementsAttribute) {
          Stack s = new Stack();
          TypeNode t = method.ReturnType;
          while (t is OptionalModifier) {
            OptionalModifier om = t as OptionalModifier;
            s.Push(om.Modifier);
            t = om.ModifiedType;
          }
          ArrayType at = t as ArrayType;
          if (at != null) { // just silently ignore if attribute is on a non-array type?
            OptionalModifier om = OptionalModifier.For(ExtendedRuntimeTypes.NonNullType, at.ElementType);
            while (0 < s.Count) {
              om = OptionalModifier.For((TypeNode)s.Pop(), om);
            }
            // also *must* make it a new array type, can't set the ElementType.
            method.ReturnType = om.GetArrayType(1);
            // Someone putting an attribute directly on the "real" method is still a
            // kind of out-of-band contract.
            // This marking is the way to signal that any override or implementing method being compiled
            // should not have its non-null annotations persisted as optional modifiers.
            method.HasOutOfBandContract = true;
          }
        }
      }
#endif
      //if ((method.Flags & MethodFlags.HasSecurity) != 0)
      //  method.SecurityAttributes = this.GetSecurityAttributesFor((index << 2)|1);
      if ((method.Flags & MethodFlags.PInvokeImpl) != 0){
        ImplMapRow[] implMaps = this.tables.ImplMapTable;
        int n = implMaps.Length, i = 0, j = n-1;
        bool sorted = (this.sortedTablesMask >> (int)TableIndices.ImplMap) % 2 == 1;
        if (sorted){
          while (i < j){
            int k = (i+j) / 2;
            if ((implMaps[k].MemberForwarded >> 1) < index)
              i = k+1;
            else
              j = k;
          }
          while (i > 0 && (implMaps[i-1].MemberForwarded>>1) == index) i--;
        }
        for (; i < n; i++){          
          ImplMapRow imr = implMaps[i];
          if (imr.MemberForwarded >> 1 == index){
            method.PInvokeFlags = (PInvokeFlags)imr.MappingFlags;
            method.PInvokeImportName = tables.GetString(imr.ImportName);
            method.PInvokeModule = this.module.ModuleReferences[imr.ImportScope-1].Module;
            break;
          }
        }
      }
      method.DeclaringType = declaringType;
      this.currentMethodTypeParameters = savedCurrentMethodTypeParameters;
      this.currentTypeParameters = savedCurrentTypeParameters;
      return method;
    }
    private void GetMethodAttributes(Method/*!*/ method, object/*!*/ handle) {
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      TypeNodeList savedCurrentMethodTypeParameters = this.currentMethodTypeParameters;
      try {
        MetadataReader tables = this.tables;
        int index = (int)handle;
        MethodRow[] methodDefs = tables.MethodTable;
        int n = methodDefs.Length;
        if (index < 1 || index > n)
          throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex);
        MethodRow md = methodDefs[index-1];
        if (method != md.Method) throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex);
        //Get custom attributes   
        method.Attributes = this.GetCustomAttributesNonNullFor((index << 5)|0);
        this.currentTypeParameters = savedCurrentTypeParameters;
        this.currentMethodTypeParameters = savedCurrentMethodTypeParameters;
        //Get security attributes
        if ((method.Flags & MethodFlags.HasSecurity) != 0)
          method.SecurityAttributes = this.GetSecurityAttributesFor((index << 2)|1);
#if !FxCop
      } catch (Exception e) {
        if (this.module != null) {
          if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
          this.module.MetadataImportErrors.Add(e);
        }
        method.Attributes = new AttributeList(0);
        this.currentTypeParameters = savedCurrentTypeParameters;
        this.currentMethodTypeParameters = savedCurrentMethodTypeParameters;
      }
#else
      }finally{}
#endif
    }
    private Method/*!*/ GetMethodFromSpec(int i) {
      MethodSpecRow[] methodSpecs = this.tables.MethodSpecTable;
      MethodSpecRow msr = methodSpecs[i-1];
      if (msr.InstantiatedMethod != null) return msr.InstantiatedMethod;
      MemoryCursor sigReader = this.tables.GetBlobCursor(msr.Instantiation);
      byte header = sigReader.ReadByte(); //skip over redundant header byte
      Debug.Assert(header == 0x0a);
      TypeNodeList templateArguments = this.ParseTypeList(sigReader);
      Method template = this.GetMethodDefOrRef(msr.Method, templateArguments.Count);
      if (template == null) return new Method();
      if (template.TemplateParameters == null) return template; //Likely a dummy method
      return template.GetTemplateInstance(this.currentType, templateArguments);
    }
    internal Member/*!*/ GetMemberFromToken(int tok, object memberInfo = null) {
      TypeNodeList varArgTypes;
      return this.GetMemberFromToken(tok, out varArgTypes, memberInfo);
    }
    internal Member/*!*/ GetMemberFromToken(int tok, out TypeNodeList varArgTypes, object memberInfo = null) {
      varArgTypes = null;
      Member member = null;
      switch ((TableIndices)(tok >> 24)){
        case TableIndices.Field : member = this.GetFieldFromDef(tok & 0xFFFFFF); break;
        case TableIndices.Method : member = this.GetMethodFromDef(tok & 0xFFFFFF); break;
        case TableIndices.MemberRef : member = this.GetMemberFromRef(tok & 0xFFFFFF, out varArgTypes, memberInfo); break;
        case TableIndices.TypeDef : member = this.GetTypeFromDef(tok & 0xFFFFFF); break;
        case TableIndices.TypeRef : member = this.GetTypeFromRef(tok & 0xFFFFFF); break;
        case TableIndices.TypeSpec : member = this.GetTypeFromSpec(tok & 0xFFFFFF); break;
        case TableIndices.MethodSpec : member = this.GetMethodFromSpec(tok & 0xFFFFFF); break;
        default: throw new InvalidMetadataException(ExceptionStrings.BadMemberToken);
      }
      if (member == null) throw new InvalidMetadataException(ExceptionStrings.BadMemberToken);
      return member;
    }
    internal Member GetMemberFromRef(int i, out TypeNodeList varArgTypes, object memberInfo = null) {
      return this.GetMemberFromRef(i, out varArgTypes, 0, memberInfo);
    }
    internal Member GetMemberFromRef(int i, out TypeNodeList varArgTypes, int numGenericArgs, object memberInfo = null) {
      MemberRefRow mref = this.tables.MemberRefTable[i-1];
      if (mref.Member != null){
        varArgTypes = mref.VarargTypes;
        return mref.Member;
      }
      varArgTypes = null;
      Member result = null;
      int codedIndex = mref.Class;
      if (codedIndex == 0) return null;
      TypeNode parent = null;
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      switch(codedIndex & 0x7){
        case 0x00 : parent = this.GetTypeFromDef(codedIndex >> 3); break;
        case 0x01 : parent = this.GetTypeFromRef(codedIndex >> 3); break;
        case 0x02 : parent = this.GetTypeGlobalMemberContainerTypeFromModule(codedIndex >> 3); break;
        case 0x03 : result = this.GetMethodFromDef(codedIndex >> 3); 
          if ((((Method)result).CallingConvention & CallingConventionFlags.VarArg) != 0){
            MemoryCursor sRdr = this.tables.GetBlobCursor(mref.Signature);
            sRdr.ReadByte(); //hdr
            int pCount = sRdr.ReadCompressedInt();
            this.ParseTypeSignature(sRdr); //rType
            bool genParameterEncountered = false;
            this.ParseParameterTypes(out varArgTypes, sRdr, pCount, ref genParameterEncountered);
          }
          goto done;
        case 0x04 : parent = this.GetTypeFromSpec(codedIndex >> 3); break;
        default: throw new InvalidMetadataException("");
      }
      if (parent != null && parent.IsGeneric){
        if (parent.Template != null)
          this.currentTypeParameters = parent.ConsolidatedTemplateArguments;
        else
          this.currentTypeParameters = parent.ConsolidatedTemplateParameters;
      }
      Identifier memberName = this.tables.GetIdentifier(mref.Name);
      Method methodToSkipPastWhenLookingForMethodParameters = null;
    tryAgain:
      MemoryCursor sigReader = this.tables.GetBlobCursor(mref.Signature);
      byte header = sigReader.ReadByte();
      if (header == 0x6){
        TypeNode fieldType = this.ParseTypeSignature(sigReader);
        TypeNode fType = TypeNode.StripModifiers(fieldType);
        TypeNode parnt = parent;
        while (parnt != null){
          MemberList members = parnt.Members;
          for (int j = 0, n = members.Count; j < n; j++){
            Field f = members[j] as Field;
            if (f == null) continue;
            if (f.Name.UniqueIdKey != memberName.UniqueIdKey) continue;
            if (TypeNode.StripModifiers(f.Type) == fType){result = f; goto done;}
          }
          Class c = parnt as Class;
          if (c != null) parnt = c.BaseClass; else break;
        }
        if (result == null){
          result = new Field(memberName);
          result.DeclaringType = parent;
          ((Field)result).Type = fieldType;
          var fieldInfo = memberInfo as FieldInfo;
          if (fieldInfo != null && fieldInfo.IsStatic)
          {
            ((Field)result).Flags |= FieldFlags.Static;
          }
          goto error;
        }
        goto done;
      }
      int typeParamCount = int.MinValue;
      CallingConventionFlags callingConvention = CallingConventionFlags.Default;
      if ((header & 0x20) != 0) callingConvention |= CallingConventionFlags.HasThis;
      if ((header & 0x40) != 0) callingConvention |= CallingConventionFlags.ExplicitThis;
      switch (header & 7){
        case 1: callingConvention |= CallingConventionFlags.C; break;
        case 2: callingConvention |= CallingConventionFlags.StandardCall; break;
        case 3: callingConvention |= CallingConventionFlags.ThisCall; break;
        case 4: callingConvention |= CallingConventionFlags.FastCall; break;
        case 5: callingConvention |= CallingConventionFlags.VarArg; break;
      }
      if ((header & 0x10) != 0){
        typeParamCount = sigReader.ReadCompressedInt();
        callingConvention |= CallingConventionFlags.Generic;
      }
      int paramCount = sigReader.ReadCompressedInt();
      TypeNodeList savedMethodTypeParameters = this.currentMethodTypeParameters;
      TypeNode pnt = parent;
      if (numGenericArgs > 0){
        bool skip = methodToSkipPastWhenLookingForMethodParameters != null;
        while (pnt != null){
          MemberList members = pnt.GetMembersNamed(memberName);        
          for (int k = 0, n = members.Count; k < n; k++){
            Method m = members[k] as Method;
            if (m == null) continue;
            if (skip) {
              if (m == methodToSkipPastWhenLookingForMethodParameters) skip = false;
              continue;
            }
            if (m.TemplateParameters == null || m.TemplateParameters.Count != numGenericArgs) continue;
            if (m.Parameters == null || m.Parameters.Count != paramCount) continue;
            this.currentMethodTypeParameters = m.TemplateParameters;
            this.currentTypeParameters = pnt.ConsolidatedTemplateArguments;
            methodToSkipPastWhenLookingForMethodParameters = m;
            goto parseSignature;
          }
          Class c = pnt as Class;
          if (c != null) pnt = c.BaseClass; else break;
        }
        methodToSkipPastWhenLookingForMethodParameters = null;
      }
    parseSignature:
      TypeNode returnType = this.ParseTypeSignature(sigReader);
      if (returnType == null) returnType = CoreSystemTypes.Object;
      bool genericParameterEncountered = returnType.IsGeneric;
      TypeNodeList paramTypes = this.ParseParameterTypes(out varArgTypes, sigReader, paramCount, ref genericParameterEncountered);
      this.currentMethodTypeParameters = savedMethodTypeParameters;
      this.currentTypeParameters = savedCurrentTypeParameters;
      pnt = parent;
      while (pnt != null){
        MemberList members = pnt.GetMembersNamed(memberName);        
        for (int k = 0, n = members.Count; k < n; k++){
          Method m = members[k] as Method;
          if (m == null) continue;
          if (m.ReturnType == null) continue;
          TypeNode mrtype = TypeNode.StripModifiers(m.ReturnType);
          //^ assert mrtype != null;
          if (!mrtype.IsStructurallyEquivalentTo(TypeNode.StripModifiers(returnType))) continue;
          if (!m.ParameterTypesMatchStructurally(paramTypes)) continue;
          if (m.CallingConvention != callingConvention) continue;
          if (typeParamCount != int.MinValue && (!m.IsGeneric || m.TemplateParameters == null || m.TemplateParameters.Count != typeParamCount))
            continue;
          result = m;
          goto done;
        }
        if (memberName.UniqueIdKey == StandardIds.Ctor.UniqueIdKey){
          //Can't run up the base class chain for constructors.
          members = pnt.GetConstructors();
          if (members != null && members.Count == 1 && paramCount == 0){
            //Only one constructor. The CLR metadata API's seem to think that this should match the empty signature
            result = members[0];
            goto done;
          }
          break;
        }
        Class c = pnt as Class;
        if (c != null)
          pnt = c.BaseClass;
        else {
          Interface iface = pnt as Interface;
          if (iface != null) {
            for (int k = 0, n = iface == null ? 0 : iface.Interfaces.Count; k < n; k++) {
              result = this.SearchBaseInterface(iface.Interfaces[k], memberName, returnType, paramTypes, typeParamCount, callingConvention);
              if (result != null) goto done;
            }
          }
          break;
        }
      }
      if (result == null){
        if (methodToSkipPastWhenLookingForMethodParameters != null) goto tryAgain;
        ParameterList parameters = new ParameterList(paramCount);
        for (int j = 0; j < paramCount; j++){
          Parameter p = new Parameter(Identifier.Empty, paramTypes[j]);
          parameters.Add(p);
        }
        //TODO: let the caller indicate if it expects a constructor
        Method meth = new Method(parent, null, memberName, parameters, returnType, null);
        meth.CallingConvention = callingConvention;
        if ((callingConvention & CallingConventionFlags.HasThis) == 0) meth.Flags |= MethodFlags.Static;
        result = meth;
      }
    error:
      if (this.module != null){
        HandleError(this.module, String.Format(CultureInfo.CurrentCulture,
          ExceptionStrings.CouldNotResolveMemberReference, parent.FullName + "::" + memberName));
        if (parent != null) parent.Members.Add(result);
      }
    done:
      if (Reader.CanCacheMember(result)) {
        this.tables.MemberRefTable[i - 1].Member = result;
        this.tables.MemberRefTable[i - 1].VarargTypes = varArgTypes;
      }
      this.currentTypeParameters = savedCurrentTypeParameters;
      return result;
    }
    private Method SearchBaseInterface(Interface iface, Identifier memberName, TypeNode returnType, TypeNodeList paramTypes, int typeParamCount, CallingConventionFlags callingConvention) {
      MemberList members = iface.GetMembersNamed(memberName);
      for (int k = 0, n = members.Count; k < n; k++) {
        Method m = members[k] as Method;
        if (m == null) continue;
        if (m.ReturnType == null) continue;
        TypeNode mrtype = TypeNode.StripModifiers(m.ReturnType);
        //^ assert mrtype != null;
        if (!mrtype.IsStructurallyEquivalentTo(TypeNode.StripModifiers(returnType))) continue;
        if (!m.ParameterTypesMatchStructurally(paramTypes)) continue;
        if (m.CallingConvention != callingConvention) continue;
        if (typeParamCount != int.MinValue && (!m.IsGeneric || m.TemplateParameters == null || m.TemplateParameters.Count != typeParamCount))
          continue;
        return m;
      }
      for (int k = 0, n = iface == null ? 0 : iface.Interfaces.Count; k < n; k++) {
        var m = this.SearchBaseInterface(iface.Interfaces[k], memberName, returnType, paramTypes, typeParamCount, callingConvention);
        if (m != null) return m;
      }
      return null;
    }
    private static bool CanCacheMethodHelper(Method/*!*/ method){
      if (method.IsGeneric) {
        if (method.TemplateArguments == null)
          return false;
        for (int i = 0; i < method.TemplateArguments.Count; i++)
          if (!CanCacheTypeNode(method.TemplateArguments[i]))
            return false;
      }
      return true;
    }
    private static bool CanCacheMember(Member/*!*/ member){
      return (member.DeclaringType == null || CanCacheTypeNode(member.DeclaringType)) &&
        (member.NodeType != NodeType.Method || CanCacheMethodHelper((Method)member));
    }

    private TypeNodeList/*!*/ ParseParameterTypes(out TypeNodeList varArgTypes, MemoryCursor/*!*/ sigReader, int paramCount, ref bool genericParameterEncountered) {
      varArgTypes = null;
      TypeNodeList paramTypes = new TypeNodeList(paramCount);
      for (int j = 0; j < paramCount; j++) {
        TypeNode paramType = this.ParseTypeSignature(sigReader);
        if (paramType == null) {
          //got a sentinel
          varArgTypes = new TypeNodeList(paramCount - j);
          j--;
          continue;
        }
        if (varArgTypes != null) { varArgTypes.Add(paramType); continue; }
        if (paramType.IsGeneric) genericParameterEncountered = true;
        paramTypes.Add(paramType);
      }
      return paramTypes;
    }
    private bool TypeDefIsClass(int i){
      if (i == 0) return false;
      TypeDefRow typeDef = this.tables.TypeDefTable[i-1];
      if (typeDef.Type != null) return typeDef.Type is Class;
      if ((typeDef.Flags & (int)TypeFlags.Interface) != 0) return false;
      return this.TypeDefOrRefOrSpecIsClassButNotValueTypeBaseClass(typeDef.Extends);
    }
    private bool TypeDefIsClassButNotValueTypeBaseClass(int i){
      if (i == 0) return false;
      TypeDefRow typeDef = this.tables.TypeDefTable[i - 1];
      if (typeDef.Type != null) return typeDef.Type != CoreSystemTypes.ValueType && typeDef.Type != CoreSystemTypes.Enum && typeDef.Type is Class;
      if ((typeDef.Flags & (int)TypeFlags.Interface) != 0) return false;
      return this.TypeDefOrRefOrSpecIsClassButNotValueTypeBaseClass(typeDef.Extends);
    }
    internal TypeNodeList GetInstantiatedTypes() {
      TypeNodeList result = null;
      TypeDefRow[] typeDefs = this.tables.TypeDefTable;
      for (int i = 0, n = typeDefs.Length; i < n; i++){
        TypeNode t = typeDefs[i].Type;
        if (t == null) continue;
        if (result == null) result = new TypeNodeList();
        result.Add(t);
      }
      return result;
    }
    internal TypeNode/*!*/ GetTypeFromDef(int i) {
      TypeDefRow typeDef = this.tables.TypeDefTable[i-1];
      if (typeDef.Type != null) return typeDef.Type;
      // Save current state because the helper might change it but this method must not.
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      TypeNode savedCurrentType = this.currentType;
      try{
        return this.GetTypeFromDefHelper(i);
#if !FxCop
      }catch(Exception e){
        if (this.module == null) return new Class();
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
        return new Class();
#endif
      }finally{
        this.currentTypeParameters = savedCurrentTypeParameters;
        this.currentType = savedCurrentType;
      }
    }
    internal TypeNode/*!*/ GetTypeFromDefHelper(int i) {
      // This is added to prevent loops. 
      //  Check the code in GetTypeFromDef which checks != null before callig this function
      this.tables.TypeDefTable[i - 1].Type = Class.Dummy;
      TypeDefRow typeDef = this.tables.TypeDefTable[i - 1];
      Identifier name = this.tables.GetIdentifier(typeDef.Name);
      Identifier namesp = this.tables.GetIdentifier(typeDef.Namespace);
      if (namesp.Name.Length > 0 && (((TypeFlags)typeDef.Flags) & TypeFlags.VisibilityMask) >= TypeFlags.NestedPublic) {
        name = Identifier.For(namesp.Name + "." + name.Name);
        namesp = Identifier.Empty;
      }
      TypeNode result = this.GetReplacedTypeFromName(namesp, name);
      if (result != null) {
        this.tables.TypeDefTable[i-1].Type = result;
        this.currentType = result;
        return result;
      }
      int firstInterfaceIndex;
      int lastInterfaceIndex;
      this.GetInterfaceIndices(i, out firstInterfaceIndex, out lastInterfaceIndex);
      InterfaceList interfaces = new InterfaceList();
      result = this.ConstructCorrectTypeNodeSubclass(i, namesp, firstInterfaceIndex, lastInterfaceIndex, 
        (TypeFlags)typeDef.Flags, interfaces, typeDef.Extends, 
        name.UniqueIdKey == StandardIds.Enum.UniqueIdKey && namesp.UniqueIdKey == StandardIds.System.UniqueIdKey);
      result.DeclaringModule = this.module;
      result.Name = name;
      result.Namespace = namesp;
      TypeNodeList typeParameters = this.currentTypeParameters = this.GetTypeParametersFor((i << 1)|0, result);
      result.TemplateParameters = typeParameters;
      result.IsGeneric = typeParameters != null;
      this.tables.TypeDefTable[i-1].Type = result;
      this.currentType = result;
      this.RemoveTypeParametersBelongingToDeclaringType(i, ref typeParameters, result);
      //Now that the type instance has been allocated, it is safe to get hold of things that could refer to this type.
      if (result is Class && result.BaseType == null){
        TypeNode baseType = this.DecodeAndGetTypeDefOrRefOrSpec(typeDef.Extends);
        ((Class)result).BaseClass = baseType as Class;
        if (baseType != null && !(baseType is Class) && this.module != null){
          HandleError(this.module, ExceptionStrings.InvalidBaseClass);
        }
      }
      if (result.IsGeneric) {
        this.GetTypeParameterConstraints((i << 1)|0, typeParameters);
        if (result.templateParameters != null) {
          for (int j = 0, offset = typeParameters.Count-result.templateParameters.Count, n = result.templateParameters.Count; j < n; j++)
            result.templateParameters[j] = typeParameters[j+offset];
        }
      }
      if (firstInterfaceIndex >= 0)
        this.GetInterfaces(i, firstInterfaceIndex, interfaces);
      if ((result.Flags & (TypeFlags.ExplicitLayout|TypeFlags.SequentialLayout)) != 0)
        this.GetClassSizeAndPackingSize(i, result);
      return result;
    }

    private void GetInterfaceIndices(int i, out int firstInterfaceIndex, out int lastInterfaceIndex) {
      firstInterfaceIndex = -1;
      lastInterfaceIndex = -1;
      InterfaceImplRow[] intfaces = this.tables.InterfaceImplTable;
      //TODO: binary search
      for (int j = 0, n = intfaces.Length; j < n; j++) {
        if (intfaces[j].Class != i) continue;
        if (firstInterfaceIndex == -1)
          firstInterfaceIndex = j;
        lastInterfaceIndex = j;
      }
    }

    private void GetClassSizeAndPackingSize(int i, TypeNode/*!*/ result) {
      ClassLayoutRow[] classLayouts = tables.ClassLayoutTable;
      for (int j = 0, n = classLayouts.Length; j < n; j++) { //TODO: binary search
        ClassLayoutRow clr = classLayouts[j];
        if (clr.Parent == i) {
          result.ClassSize = clr.ClassSize;
          result.PackingSize = clr.PackingSize;
          break;
        }
      }
    }

    private void GetInterfaces(int i, int firstInterfaceIndex, InterfaceList/*!*/ interfaces) {
      InterfaceImplRow[] intfaces = this.tables.InterfaceImplTable;
      for (int j = firstInterfaceIndex, n = intfaces.Length; j < n; j++) {
        if (intfaces[j].Class != i) continue; //TODO: break if sorted
        TypeNode ifaceT = this.DecodeAndGetTypeDefOrRefOrSpec(intfaces[j].Interface);
        Interface iface = ifaceT as Interface;
        if (iface == null) {
          iface = new Interface();
          if (ifaceT != null) {
            iface.DeclaringModule = ifaceT.DeclaringModule;
            iface.Namespace = ifaceT.Namespace;
            iface.Name = ifaceT.Name;
          }
        }
        interfaces.Add(iface);
        var implAttrs = this.GetCustomAttributesFor((j << 5)|5);
        if (implAttrs != null)
          interfaces.AddAttributes(interfaces.Count-1, implAttrs);
      }
    }

    private void RemoveTypeParametersBelongingToDeclaringType(int i, ref TypeNodeList typeParameters, TypeNode/*!*/ type) {
      NestedClassRow[] nestedClasses = tables.NestedClassTable;
      for (int j = 0, n = nestedClasses.Length; j < n; j++) { //TODO: binary search
        NestedClassRow ncr = nestedClasses[j];
        if (ncr.NestedClass == i) {
          type.DeclaringType = this.GetTypeFromDef(ncr.EnclosingClass);
          if (type.DeclaringType != null && type.DeclaringType.IsGeneric) {
            //remove type parameters that belong to declaring type from nested type's list
            if (type.templateParameters != null) {
              int icount = GetInheritedTypeParameterCount(type);
              int rcount = type.templateParameters.Count;
              if (icount >= rcount)
                type.templateParameters = null;
              else {
                TypeNodeList tpars = new TypeNodeList(rcount - icount);
                for (int k = icount; k < rcount; k++)
                  tpars.Add(type.templateParameters[k]);
                type.templateParameters = tpars;
              }
              this.currentTypeParameters = typeParameters = type.ConsolidatedTemplateParameters;
            }
          }
          break;
        }
      }
    }

    private TypeNode/*!*/ ConstructCorrectTypeNodeSubclass(int i, Identifier/*!*/ namesp, int firstInterfaceIndex, int lastInterfaceIndex,
      TypeFlags flags, InterfaceList interfaces, int baseTypeCodedIndex, bool isSystemEnum){
      TypeNode result;
      TypeNode.TypeAttributeProvider attributeProvider = new TypeNode.TypeAttributeProvider(this.GetTypeAttributes);
      TypeNode.NestedTypeProvider nestedTypeProvider = new TypeNode.NestedTypeProvider(this.GetNestedTypes);
      TypeNode.TypeMemberProvider memberProvider = new TypeNode.TypeMemberProvider(this.GetTypeMembers);
      bool isTemplateParameter = false;
#if ExtendedRuntime
      InterfaceImplRow[] intfaces = this.tables.InterfaceImplTable;
      Interface firstInterface = null;
      Interface lastInterface = null;
      if (firstInterfaceIndex >= 0){
        firstInterface = this.GetInterfaceIfNotGenericInstance(intfaces[firstInterfaceIndex].Interface);
        if (firstInterface != null){
          lastInterface = this.GetInterfaceIfNotGenericInstance(intfaces[lastInterfaceIndex].Interface);
          isTemplateParameter = CoreSystemTypes.IsInitialized && lastInterface != null && lastInterface == ExtendedRuntimeTypes.ITemplateParameter;
        }
      }        
#endif
      if ((flags & TypeFlags.Interface) != 0){
        if (isTemplateParameter)
          result = new TypeParameter(interfaces, nestedTypeProvider, attributeProvider, memberProvider, i);
        else
          result = new Interface(interfaces, nestedTypeProvider, attributeProvider, memberProvider, i);
      }else if (isTemplateParameter){
        result = new ClassParameter(nestedTypeProvider, attributeProvider, memberProvider, i);
      }else{
        result = null;
        TypeNode baseClass = this.GetTypeIfNotGenericInstance(baseTypeCodedIndex);
        if (baseClass != null){
          if (baseClass == CoreSystemTypes.MulticastDelegate) //TODO: handle single cast delegates
            result = new DelegateNode(nestedTypeProvider, attributeProvider, memberProvider, i);
          else if (baseClass == CoreSystemTypes.Enum || baseClass.Namespace.UniqueIdKey==StandardIds.System.UniqueIdKey && baseClass.Name.UniqueIdKey == StandardIds.Enum.UniqueIdKey)
            result = new EnumNode(nestedTypeProvider, attributeProvider, memberProvider, i);
          else if (baseClass == CoreSystemTypes.ValueType &&
            !(isSystemEnum && (flags & TypeFlags.Sealed) == 0)){
#if ExtendedRuntime
            Struct st = null;
            if (firstInterface != null){
              if (namesp.UniqueIdKey == StandardIds.StructuralTypes.UniqueIdKey){
                if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.TupleType)
                  st = new TupleType(nestedTypeProvider, attributeProvider, memberProvider, i);
                else if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.TypeIntersection)
                  st = new TypeIntersection(nestedTypeProvider, attributeProvider, memberProvider, i);
                else if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.TypeUnion)
                  st = new TypeUnion(nestedTypeProvider, attributeProvider, memberProvider, i);
                else if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.ConstrainedType)
                  st = new ConstrainedType(nestedTypeProvider, attributeProvider, memberProvider, i);
                else
                  st = new Struct(nestedTypeProvider, attributeProvider, memberProvider, i);
              }
              else if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.TypeAlias)
                st = new TypeAlias(nestedTypeProvider, attributeProvider, memberProvider, i, false);
              else if (CoreSystemTypes.IsInitialized && firstInterface == ExtendedRuntimeTypes.TypeDefinition)
                st = new TypeAlias(nestedTypeProvider, attributeProvider, memberProvider, i, true);
            }
            if (st == null && lastInterface != null) {
              result = this.GetTypeExtensionFromDef(nestedTypeProvider, attributeProvider, memberProvider, i, baseClass, lastInterface);
            }
            else {
              result = st;
            }
            if (result == null)
#endif
              result = new Struct(nestedTypeProvider, attributeProvider, memberProvider, i);
          }
        }
        if (result == null){
#if ExtendedRuntime
          if (lastInterface != null)
            result = this.GetTypeExtensionFromDef(nestedTypeProvider, attributeProvider, memberProvider, i, baseClass, lastInterface);
          if (result == null)
#endif
            result = new Class(nestedTypeProvider, attributeProvider, memberProvider, i);
        }
      }
      result.Flags = flags;
      result.Interfaces = interfaces;
      return result;
    }
#if !MinimalReader
    private TrivialHashtable/*<Ident,TypeExtensionProvider>*//*!*/ TypeExtensionTable = new TrivialHashtable();
    delegate TypeNode TypeExtensionProvider(TypeNode.NestedTypeProvider nprovider, TypeNode.TypeAttributeProvider aprovider, TypeNode.TypeMemberProvider mprovider, TypeNode baseType, object handle);

    private static TypeNode DummyTypeExtensionProvider(TypeNode.NestedTypeProvider nprovider, TypeNode.TypeAttributeProvider aprovider, TypeNode.TypeMemberProvider mprovider, TypeNode baseType, object handle) {
      return null;
    }
    private TypeExtensionProvider/*!*/ dummyTEProvider = new TypeExtensionProvider(DummyTypeExtensionProvider);

    private TypeNode GetTypeExtensionFromDef(TypeNode.NestedTypeProvider nestedTypeProvider, TypeNode.TypeAttributeProvider attributeProvider, TypeNode.TypeMemberProvider memberProvider, object handle, TypeNode baseType, Interface/*!*/ lastInterface) {
      if (lastInterface.Namespace.UniqueIdKey == StandardIds.CciTypeExtensions.UniqueIdKey) {
        TypeExtensionProvider teprovider = (TypeExtensionProvider)TypeExtensionTable[lastInterface.Name.UniqueIdKey];
        if (teprovider == null) {
          string loc = lastInterface.DeclaringModule.Location.ToLower(CultureInfo.InvariantCulture);
          if (loc.EndsWith(".runtime.dll")) {
            loc = System.IO.Path.GetFileName(loc);
            string compilerDllName = loc.Replace(".runtime.dll", "");
            System.Reflection.Assembly rassem;
            try{
              rassem = System.Reflection.Assembly.Load(compilerDllName);
            }catch{
              HandleError(this.module, string.Format(CultureInfo.CurrentCulture, ExceptionStrings.CannotLoadTypeExtension, lastInterface.FullName, compilerDllName));
              goto ExtensionNotFound;
            }
            if (rassem == null) goto ExtensionNotFound;  
            System.Type tprov = rassem.GetType(StandardIds.CciTypeExtensions.Name+"."+lastInterface.Name.Name+"Provider");
            if (tprov == null) goto ExtensionNotFound;
            System.Reflection.MethodInfo providerMethod = tprov.GetMethod("For");
            if (providerMethod == null) goto ExtensionNotFound;
            teprovider = (TypeExtensionProvider)Delegate.CreateDelegate(typeof(TypeExtensionProvider), providerMethod);
          ExtensionNotFound: ;
            if (teprovider == null) {
              // install a not-found dummy provider
              teprovider = this.dummyTEProvider;
            }
            TypeExtensionTable[lastInterface.Name.UniqueIdKey] = teprovider;
          }
        }
        if (teprovider == null) return null;
        return teprovider(nestedTypeProvider, attributeProvider, memberProvider, baseType, handle);
      }
      return null;
    }
#endif
    private static int GetInheritedTypeParameterCount(TypeNode type){
      if (type == null) return 0;
      int n = 0;
      type = type.DeclaringType;
      while (type != null){
        n += type.templateParameters == null ? 0 : type.templateParameters.Count;
        type = type.DeclaringType;
      }
      return n;
    }
    private TypeNode/*!*/ GetTypeGlobalMemberContainerTypeFromModule(int i){
      ModuleRefRow mr = this.tables.ModuleRefTable[i-1];
      Module mod = mr.Module;
      TypeNode result = null;
      if (mod != null && mod.Types != null && mod.Types.Count > 0)
        result = mod.Types[0];
      if (result != null) return result;
      result = this.GetDummyTypeNode(Identifier.Empty, Identifier.For("<Module>"), mod, null, false);
      if (mod != null) mod.Types = new TypeNodeList(result);
      return result;
    }
    internal void GetNamespaces()
       //^ ensures this.namespaceTable != null;
    {
      TypeDefRow[] typeDefs = this.tables.TypeDefTable;
      int n = typeDefs.Length;
      TrivialHashtable nsT = this.namespaceTable = new TrivialHashtable(n);
      TrivialHashtable nsFor = new TrivialHashtable(128);
      NamespaceList nsL = this.namespaceList = new NamespaceList(n);
      for (int i = 0; i < n; i++){
        TypeDefRow typeDef = typeDefs[i];
        TrivialHashtable ns = (TrivialHashtable)nsT[typeDef.NamespaceKey];
        Namespace nSpace = (Namespace)nsFor[typeDef.NamespaceKey];
        if (ns == null){
          nsT[typeDef.NamespaceKey] = ns = new TrivialHashtable();
          nsFor[typeDef.NamespaceKey] = nSpace = new Namespace(typeDef.NamespaceId);
          nsL.Add(nSpace);
        }
        Debug.Assert(nSpace != null);
        if ((typeDef.Flags & (int)TypeFlags.VisibilityMask) == 0)
          ns[typeDef.NameKey] = i+1;
        else if ((typeDef.Flags & (int)TypeFlags.VisibilityMask) == 1){
          nSpace.isPublic = true;
          ns[typeDef.NameKey] = i+1;
        }
      }
    }
    private TypeNode GetTypeFromName(Identifier/*!*/ Namespace, Identifier/*!*/ name) {
      try{
        if (this.namespaceTable == null) this.GetNamespaces();
        //^ assert this.namespaceTable != null;
        TrivialHashtable nsTable = (TrivialHashtable)this.namespaceTable[Namespace.UniqueIdKey];
        if (nsTable == null) return this.GetForwardedTypeFromName(Namespace, name);
        object ti = nsTable[name.UniqueIdKey];
        if (ti == null) return this.GetForwardedTypeFromName(Namespace, name);
        TypeNode t = this.GetTypeFromDef((int)ti);
        return t;
#if !FxCop
      }catch(Exception e){
        if (this.module == null) return null;
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
        return null;
      }
#else
      }finally{}
#endif
    }
    private TypeNode GetForwardedTypeFromName(Identifier/*!*/ Namespace, Identifier/*!*/ name) {
      ExportedTypeRow[] exportedTypes = this.tables.ExportedTypeTable;
      for (int i = 0, n = exportedTypes == null ? 0 : exportedTypes.Length; i < n; i++) {
        ExportedTypeRow etr = exportedTypes[i];
        if ((etr.Flags & (int)TypeFlags.Forwarder) == 0) continue;
        if (this.tables.GetString(etr.TypeNamespace) != Namespace.Name ||
            this.tables.GetString(etr.TypeName) != name.Name) continue;
        int index = etr.Implementation >> 2;
        AssemblyRefRow arr = this.tables.AssemblyRefTable[index - 1];
        return arr.AssemblyReference.Assembly.GetType(Namespace, name);
      }
      return this.GetReplacedTypeFromName(Namespace, name);
    }
    private TypeNode GetReplacedTypeFromName(Identifier/*!*/ Namespace, Identifier/*!*/ name) {
#if !MinimalReader
      if (this.module.ContainingAssembly == null || (this.module.ContainingAssembly.Flags & AssemblyFlags.ContainsForeignTypes) == 0) return null;
      if (!SystemTypes.Initialized || this.module.ContainingAssembly == null) return null;
      int nsKey = Namespace.UniqueIdKey;
      int nKey = name.UniqueIdKey;
      if (nsKey == StandardIds.WindowsFoundationMetadata.UniqueIdKey) {
        if (nKey == SystemTypes.AttributeUsageAttribute.Name.UniqueIdKey) return SystemTypes.AttributeUsageAttribute;
        if (nKey == SystemTypes.AttributeTargets.Name.UniqueIdKey) return SystemTypes.AttributeTargets;
      } else if (nsKey == StandardIds.WindowsUI.UniqueIdKey) {
        if (nKey == SystemTypes.Color.Name.UniqueIdKey && SystemTypes.Color.DeclaringModule.Location != "unknown:location") return SystemTypes.Color;
      } else if (nsKey == StandardIds.WindowsFoundation.UniqueIdKey) {
        if (nKey == SystemTypes.DateTime.Name.UniqueIdKey) return SystemTypes.DateTimeOffset;
        if (SystemTypes.EventHandler1 != null && nKey == SystemTypes.EventHandler1.Name.UniqueIdKey) return SystemTypes.EventHandler1;
        if (nKey == SystemTypes.EventRegistrationToken.Name.UniqueIdKey) return SystemTypes.EventRegistrationToken;
        if (nKey == StandardIds.HResult.UniqueIdKey) return SystemTypes.Exception;
        if (nKey == StandardIds.IReference1.UniqueIdKey) return SystemTypes.GenericNullable;
        if (nKey == SystemTypes.Point.Name.UniqueIdKey) return SystemTypes.Point;
        if (nKey == SystemTypes.Rect.Name.UniqueIdKey) return SystemTypes.Rect;
        if (nKey == SystemTypes.Size.Name.UniqueIdKey) return SystemTypes.Size;
        if (nKey == SystemTypes.TimeSpan.Name.UniqueIdKey) return SystemTypes.TimeSpan;
        if (nKey == SystemTypes.Uri.Name.UniqueIdKey) return SystemTypes.Uri;
        if (nKey == StandardIds.IClosable.UniqueIdKey) return SystemTypes.IDisposable;
      } else if (nsKey == StandardIds.WindowsFoundationCollections.UniqueIdKey) {
        if (nKey == StandardIds.IIterable1.UniqueIdKey) return SystemTypes.GenericIEnumerable;
        if (nKey == StandardIds.IVector1.UniqueIdKey) return SystemTypes.GenericIList;
        if (nKey == StandardIds.IVectorView1.UniqueIdKey) return SystemTypes.GenericIReadOnlyList;
        if (nKey == StandardIds.IMap2.UniqueIdKey) return SystemTypes.GenericIDictionary;
        if (nKey == StandardIds.IMapView2.UniqueIdKey) return SystemTypes.GenericIReadOnlyDictionary;
        if (nKey == StandardIds.IKeyValuePair2.UniqueIdKey) return SystemTypes.GenericKeyValuePair;
      } else if (nsKey == StandardIds.WindowsUIXaml.UniqueIdKey) {
        if (nKey == SystemTypes.CornerRadius.Name.UniqueIdKey && SystemTypes.CornerRadius.DeclaringModule.Location != "unknown:location") return SystemTypes.CornerRadius;
        if (nKey == SystemTypes.Duration.Name.UniqueIdKey && SystemTypes.Duration.DeclaringModule.Location != "unknown:location") return SystemTypes.Duration;
        if (SystemTypes.DurationType != null && nKey == SystemTypes.DurationType.Name.UniqueIdKey) return SystemTypes.DurationType;
        if (nKey == SystemTypes.GridLength.Name.UniqueIdKey && SystemTypes.GridLength.DeclaringModule.Location != "unknown:location") return SystemTypes.GridLength;
        if (SystemTypes.GridUnitType != null && nKey == SystemTypes.GridUnitType.Name.UniqueIdKey) return SystemTypes.GridUnitType;
        if (nKey == SystemTypes.Thickness.Name.UniqueIdKey && SystemTypes.Thickness.DeclaringModule.Location != "unknown:location") return SystemTypes.Thickness;
      } else if (nsKey == StandardIds.WindowsUIXamlData.UniqueIdKey) {
        if (nKey == SystemTypes.INotifyPropertyChanged.Name.UniqueIdKey && SystemTypes.INotifyPropertyChanged.DeclaringModule.Location != "unknown:location") return SystemTypes.INotifyPropertyChanged;
        if (nKey == SystemTypes.PropertyChangedEventHandler.Name.UniqueIdKey && SystemTypes.PropertyChangedEventHandler.DeclaringModule.Location != "unknown:location") return SystemTypes.PropertyChangedEventHandler;
        if (nKey == SystemTypes.PropertyChangedEventArgs.Name.UniqueIdKey && SystemTypes.PropertyChangedEventArgs.DeclaringModule.Location != "unknown:location") return SystemTypes.PropertyChangedEventArgs;
      } else if (nsKey == StandardIds.WindowsUIXamlInput.UniqueIdKey) {
        if (nKey == StandardIds.ICommand.UniqueIdKey) return SystemTypes.ICommand;
      } else if (nsKey == StandardIds.WindowsUIXamlInterop.UniqueIdKey) {
        if (nKey == StandardIds.IBindableIterable.UniqueIdKey) return SystemTypes.IBindableIterable;
        if (nKey == StandardIds.IBindableVector.UniqueIdKey) return SystemTypes.IBindableVector;
        if (nKey == StandardIds.INotifyCollectionChanged.UniqueIdKey) return SystemTypes.INotifyCollectionChanged;
        if (nKey == StandardIds.NotifyCollectionChangedAction.UniqueIdKey) return SystemTypes.NotifyCollectionChangedAction;
        if (nKey == StandardIds.NotifyCollectionChangedEventArgs.UniqueIdKey) return SystemTypes.NotifyCollectionChangedEventArgs;
        if (nKey == StandardIds.NotifyCollectionChangedEventHandler.UniqueIdKey) return SystemTypes.NotifyCollectionChangedEventHandler;
        if (nKey == StandardIds.TypeName.UniqueIdKey) return SystemTypes.Type;
      } else if (nsKey == StandardIds.WindowsUIXamlControlsPrimitives.UniqueIdKey) {
        if (nKey == SystemTypes.GeneratorPosition.Name.UniqueIdKey && SystemTypes.GeneratorPosition.DeclaringModule.Location != "unknown:location") return SystemTypes.GeneratorPosition;
      } else if (nsKey == StandardIds.WindowsUIXamlMedia.UniqueIdKey) {
        if (nKey == SystemTypes.Matrix.Name.UniqueIdKey && SystemTypes.Matrix.DeclaringModule.Location != "unknown:location") return SystemTypes.Matrix;
      } else if (nsKey == StandardIds.WindowsUIXamlMediaAnimation.UniqueIdKey) {
        if (nKey == SystemTypes.KeyTime.Name.UniqueIdKey && SystemTypes.KeyTime.DeclaringModule.Location != "unknown:location") return SystemTypes.KeyTime;
        if (nKey == SystemTypes.RepeatBehavior.Name.UniqueIdKey && SystemTypes.KeyTime.DeclaringModule.Location != "unknown:location") return SystemTypes.RepeatBehavior;
        if (SystemTypes.RepeatBehaviorType != null && nKey == SystemTypes.RepeatBehaviorType.Name.UniqueIdKey) return SystemTypes.RepeatBehaviorType;
      } else if (nsKey == StandardIds.WindowsUIXamlMediaMedia3D.UniqueIdKey) {
        if (nKey == SystemTypes.Matrix3D.Name.UniqueIdKey && SystemTypes.Matrix3D.DeclaringModule.Location != "unknown:location") return SystemTypes.Matrix3D;
      }
#endif
      return null;
    }
    internal bool IsValidTypeName(Identifier/*!*/ Namespace, Identifier/*!*/ name) {
      try{
        if (this.namespaceTable == null) this.GetNamespaces();
        //^ assert this.namespaceTable != null;
        TrivialHashtable nsTable = (TrivialHashtable)this.namespaceTable[Namespace.UniqueIdKey];
        if (nsTable == null) return false;
        return nsTable[name.UniqueIdKey] != null;
#if !FxCop
      }catch(Exception e){
        if (this.module == null) return false;
        if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
        this.module.MetadataImportErrors.Add(e);
        return false;
      }
#else
      }finally{}
#endif
    }
    internal TypeNode/*!*/ GetTypeFromRef(int i) {
      return this.GetTypeFromRef(i, false);
    }
    internal TypeNode/*!*/ GetTypeFromRef(int i, bool expectStruct) {
      TypeRefRow[] trtable = this.tables.TypeRefTable;
      TypeRefRow trr = trtable[i-1];
      TypeNode result = trr.Type;
      if (result != null) return result;
      Identifier name = tables.GetIdentifier(trr.Name);
      Identifier namesp = tables.GetIdentifier(trr.Namespace);
      int resolutionScope = trr.ResolutionScope;
      Module declaringModule = null;
      TypeNode declaringType = null;
      int index = resolutionScope >> 2;
      switch (resolutionScope & 0x3){
        case 0:
          declaringModule = this.module;
          //^ assume declaringModule != null;
          result = declaringModule.GetType(namesp, name);
          //REVIEW: deal with case where ref is in same (multi-module) assembly, but not the current module? index == 0
          break;
        case 1: 
          declaringModule = this.tables.ModuleRefTable[index-1].Module;
          if (declaringModule != null)
            result = declaringModule.GetType(namesp, name);
          break; 
        case 2:
          if (index > 0)
            declaringModule = this.tables.AssemblyRefTable[index - 1].AssemblyReference.Assembly;
          if (declaringModule != null)
            result = declaringModule.GetType(namesp, name);
          break;
        case 3: 
          declaringType = this.GetTypeFromRef(index);
          declaringModule = declaringType.DeclaringModule;
          if (namesp == null || namesp.length == 0)
            result = (TypeNode)declaringType.GetMembersNamed(name)[0];
          else
            result = (TypeNode)declaringType.GetMembersNamed(Identifier.For(namesp.Name+"."+name.Name))[0];
          break;
        default: 
          declaringModule = this.module;
          break;
      }
      if (result == null)
        result = this.GetDummyTypeNode(namesp, name, declaringModule, declaringType, expectStruct);
      trtable[i-1].Type = result;
      if (!Reader.CanCacheTypeNode(result))
        trtable[i-1].Type = null;
      return result;
    }
    private TypeNode/*!*/ GetDummyTypeNode(Identifier namesp, Identifier name, Module declaringModule, TypeNode declaringType, bool expectStruct) {
      TypeNode result = null;
      if (this.module != null) {
        string modName = declaringModule == null ? "" : declaringModule.Name == null ? "" : declaringModule.Name.ToString();
        string context = declaringType != null ? declaringType.FullName: (namesp!=null)?namesp.Name:null;
        HandleError(this.module, String.Format(CultureInfo.CurrentCulture, ExceptionStrings.CouldNotResolveTypeReference,
          "["+modName+"]"+context+"."+name));
      }
      result = expectStruct ? (TypeNode)new Struct() : (TypeNode)new Class();
      if (name != null && name.ToString().StartsWith("I") && name.ToString().Length > 1 && char.IsUpper(name.ToString()[1]))
        result = new Interface();
      result.Flags |= TypeFlags.Public;
      result.Name = name;
      result.Namespace = namesp;
      if (declaringType != null) {
        result.DeclaringType = declaringType;
        result.DeclaringType.DeclaringModule = declaringType.DeclaringModule;
        declaringType.Members.Add(result);
      } else {
        if (declaringModule == null) declaringModule = this.module;
        //^ assume declaringModule != null;
        result.DeclaringModule = declaringModule;
        if (declaringModule.types != null)
          declaringModule.types.Add(result);
      }
      return result;
    }
    private bool TypeSpecIsClass(int i){
      TypeSpecRow tsr = this.tables.TypeSpecTable[i-1];
      if (tsr.Type != null) return tsr.Type is Class;
      this.tables.GetSignatureLength(tsr.Signature);
      return this.TypeSignatureIsClass(this.tables.GetNewCursor());
    }
    internal TypeNode/*!*/ GetTypeFromSpec(int i) {
      TypeSpecRow tsr = this.tables.TypeSpecTable[i-1];
      if (tsr.Type != null) return tsr.Type;
      this.tables.GetSignatureLength(tsr.Signature);
      bool pinned = false;
      bool isTypeArgument = false;
      TypeNode result = this.ParseTypeSignature(this.tables.GetNewCursor(), ref pinned, ref isTypeArgument);
      if (result == null) result = new Class();
      //Get custom attributes
      AttributeList attributes = this.GetCustomAttributesFor((i << 5) | 13);
      if (attributes != null && attributes.Count > 0) {
        //Append attributes "inherited" from template to metadata attributes
        AttributeList templAttributes = result.Attributes;
        for (int j = 0, n = templAttributes == null ? 0 : templAttributes.Count; j < n; j++) {
          AttributeNode attr = result.Attributes[j];
          if (attr == null) continue;
          attributes.Add(attr);
        }
        result.Attributes = attributes;
      }
#if ExtendedRuntime
      for (int j = 0, n = attributes.Count; j < n; j++) {
        if (attributes[j].Type == SystemTypes.NotNullGenericArgumentsAttribute) {
          Literal l = (Literal)attributes[j].Expressions[0];
          string s = (string)l.Value;
          TypeNodeList ts = new TypeNodeList(s.Length);
          for (int k = 0, m = s.Length; k < m; k++) {
            if (s[k] == '!')
              ts.Add(OptionalModifier.For(ExtendedRuntimeTypes.NonNullType, result.ConsolidatedTemplateArguments[k]));
            else
              ts.Add(result.ConsolidatedTemplateArguments[k]);
          }
          result = result.Template.GetGenericTemplateInstance(this.module, ts);
          //^ assume result != null;
        }
      }
#endif
      if (!isTypeArgument && Reader.CanCacheTypeNode(result))
        this.tables.TypeSpecTable[i-1].Type = result;
      return result;
    }
    private static bool CanCacheTypeNode(TypeNode/*!*/ type) {
#if WHIDBEY
      if (!type.IsGeneric && (type.Template == null || !type.IsNotFullySpecialized) &&
      type.NodeType != NodeType.TypeParameter && type.NodeType != NodeType.ClassParameter &&
      type.NodeType != NodeType.InterfaceExpression) {
        TypeNodeList elementTypes = type.StructuralElementTypes;
        for (int i = 0, n = elementTypes == null ? 0 : elementTypes.Count; i < n; i++)
          if (!CanCacheTypeNode(type.StructuralElementTypes[i])) return false;
        return true;
      }
      return false;
#else
      return true;
#endif
    }
    private static Module GetNestedModule(Module module, string modName, ref string modLocation){
      if (module == null || modName == null){Debug.Assert(false); return null;}
      Module mod = module.GetNestedModule(modName);
      if (mod == null){
        if (module.Location != null)
          modLocation = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(module.Location), modName);
        if (modLocation != null && System.IO.File.Exists(modLocation)){
          mod = Module.GetModule(modLocation);
          if (mod != null){
            mod.ContainingAssembly = module.ContainingAssembly;
            module.ModuleReferences.Add(new ModuleReference(modName, mod));
          }
        }
      }
      if (mod == null){
        HandleError(module, String.Format(CultureInfo.CurrentCulture,
          ExceptionStrings.CouldNotFindReferencedModule,modLocation));
        mod = new Module();
        mod.Name = modName;
        mod.ContainingAssembly = module.ContainingAssembly;
        mod.Kind = ModuleKindFlags.DynamicallyLinkedLibrary;
      }
      return mod;
    }
    private void GetTypeList(Module/*!*/ module) {
      TypeNodeList types = new TypeNodeList();
      TypeDefRow[] typeDefs = this.tables.TypeDefTable;
      for (int i = 0, n = typeDefs.Length; i < n; i++){
        TypeNode t = this.GetTypeFromDef(i+1);
        if (t != null && t.DeclaringType == null) types.Add(t);
      }
      module.Types = types;
      AssemblyNode assem = module as AssemblyNode;
      if (assem == null) return;
      types = new TypeNodeList();
      ExportedTypeRow[] exportedTypes = this.tables.ExportedTypeTable;
      for (int i = 0, n = exportedTypes.Length; i < n; i++){
        ExportedTypeRow etr = exportedTypes[i];
        Identifier nameSpace = Identifier.For(this.tables.GetString(etr.TypeNamespace));
        Identifier typeName = Identifier.For(this.tables.GetString(etr.TypeName));
        TypeNode exportedType = null;
        switch (etr.Implementation & 0x3){
          case 0:
            string modName = this.tables.GetString(this.tables.FileTable[(etr.Implementation >> 2)-1].Name);
            string modLocation = modName;
            Module mod = GetNestedModule(assem, modName, ref modLocation);
            if (mod == null){Debug.Assert(false); break;}
            exportedType = mod.GetType(nameSpace, typeName);
            if (exportedType == null){
              HandleError(assem, String.Format(CultureInfo.CurrentCulture,
                ExceptionStrings.CouldNotFindExportedTypeInModule, nameSpace+"."+typeName, modLocation));
              exportedType = new Class();
              exportedType.Name = typeName;
              exportedType.Namespace = nameSpace;
              exportedType.Flags = TypeFlags.Class|TypeFlags.Public;
              exportedType.DeclaringModule = mod;
            }
            break;
          case 1:
            AssemblyReference aref = this.tables.AssemblyRefTable[(etr.Implementation >> 2)-1].AssemblyReference;
            if (aref == null){
              HandleError(assem, ExceptionStrings.BadMetadataInExportTypeTableNoSuchAssemblyReference);
              aref = new AssemblyReference("dummy assembly for bad reference");
            }
            AssemblyNode a = aref.Assembly;
            if (a == null){Debug.Assert(false); continue;}
            exportedType = a.GetType(nameSpace, typeName);
            if (exportedType == null){
              HandleError(assem, String.Format(CultureInfo.CurrentCulture, 
                ExceptionStrings.CouldNotFindExportedTypeInAssembly, nameSpace+"."+typeName, a.StrongName));
              exportedType = new Class();
              exportedType.Name = typeName;
              exportedType.Namespace = nameSpace;
              exportedType.Flags = TypeFlags.Class|TypeFlags.Public;
              exportedType.DeclaringModule = a;
            }
            break;
          case 2:
            TypeNode parentType = types[(etr.Implementation >> 2)-1];
            if (parentType == null){
              HandleError(assem, ExceptionStrings.BadMetadataInExportTypeTableNoSuchParentType);
              parentType = new Class();
              parentType.DeclaringModule = this.module;
              parentType.Name = Identifier.For("Missing parent type");
            }
            exportedType = parentType.GetNestedType(typeName);
            if (exportedType == null){
              HandleError(assem, String.Format(CultureInfo.CurrentCulture,
                ExceptionStrings.CouldNotFindExportedNestedTypeInType, typeName, parentType.FullName));
              exportedType = new Class();
              exportedType.Name = typeName;
              exportedType.Flags = TypeFlags.Class|TypeFlags.NestedPublic;
              exportedType.DeclaringType = parentType;
              exportedType.DeclaringModule = parentType.DeclaringModule;
            }
            break;
        }
        types.Add(exportedType);
      }
      assem.ExportedTypes = types;
    }
    private void GetNestedTypes(TypeNode/*!*/ type, object/*!*/ handle) {
      type.nestedTypes = null;
      TypeNodeList result = new TypeNodeList();
#if !FxCop
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      TypeNode savedCurrentType = this.currentType;
#endif
      try{
        if (type.IsGeneric){
          if (type.templateParameters == null) type.templateParameters = new TypeNodeList(0);
          this.currentTypeParameters = type.ConsolidatedTemplateParameters;
        }
        this.currentType = type;
        TypeNode declaringType = type.DeclaringType;
        while (this.currentTypeParameters == null && declaringType != null){
          if (declaringType.IsGeneric) {
            if (declaringType.templateParameters == null) declaringType.templateParameters = new TypeNodeList(0);
            this.currentTypeParameters = declaringType.ConsolidatedTemplateParameters;
          }
          declaringType = declaringType.DeclaringType;
        }
        MetadataReader tables = this.tables;
        int typeTableIndex = (int)handle;
        TypeDefRow[] typeDefs = tables.TypeDefTable;
        int n = typeDefs.Length;
        if (typeTableIndex < 1 || typeTableIndex > n)
          throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex);
        NestedClassRow[] nestedClasses = tables.NestedClassTable;
        n = nestedClasses.Length;
        for (int i = 0; i < n; i++){ //TODO: binary lookup
          NestedClassRow ncr = nestedClasses[i];
          if (ncr.EnclosingClass != typeTableIndex) continue;
          TypeNode t = this.GetTypeFromDef(ncr.NestedClass);
          if (t != null) {
            if (type.nestedTypes != null) return; //A recursive call to GetNestedTypes has already done the deed
            t.DeclaringType = type;
            if ((t.Flags & TypeFlags.RTSpecialName) == 0 || t.Name.UniqueIdKey != StandardIds._Deleted.UniqueIdKey)
              result.Add(t);
          } else {
            throw new InvalidMetadataException("Invalid nested class row");
          }
        }
        type.nestedTypes = result;
#if !FxCop
      }catch (Exception e){
        if (this.module != null){
          if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
          this.module.MetadataImportErrors.Add(e);
        }
      }
      finally{
        this.currentTypeParameters = savedCurrentTypeParameters;
        this.currentType = savedCurrentType;
      }
#else
      }finally{}
#endif
    }
    private void GetTypeMembers(TypeNode/*!*/ type, object/*!*/ handle) {
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      TypeNode savedCurrentType = this.currentType;
      try{
        MetadataReader tables = this.tables;
        int typeTableIndex = (int)handle;
        TypeDefRow[] typeDefs = tables.TypeDefTable;
        FieldRow[] fieldDefs = tables.FieldTable;
        FieldPtrRow[] fieldPtrs = tables.FieldPtrTable;
        MethodRow[] methodDefs = tables.MethodTable;
        MethodPtrRow[] methodPtrs = tables.MethodPtrTable;
        EventMapRow[] eventMaps = tables.EventMapTable;
        EventRow[] eventDefs = tables.EventTable;
        EventPtrRow[] eventPtrs = tables.EventPtrTable;
        MethodImplRow[] methodImpls = tables.MethodImplTable;
        PropertyMapRow[] propertyMaps = tables.PropertyMapTable;
        PropertyPtrRow[] propertyPtrs = tables.PropertyPtrTable;
        PropertyRow[] propertyDefs = this.tables.PropertyTable;
        NestedClassRow[] nestedClasses = tables.NestedClassTable;
        int n = typeDefs.Length;
        if (typeTableIndex < 1 || typeTableIndex > n)
          throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex);
        TypeDefRow td = typeDefs[typeTableIndex-1];
        if (type != td.Type) throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex);
        //Get type members
        if (type.IsGeneric){
          if (type.templateParameters == null) type.templateParameters = new TypeNodeList(0);
          this.currentTypeParameters = type.ConsolidatedTemplateParameters;
        }
        this.currentType = type;
        TypeNode declaringType = type.DeclaringType;
        while (this.currentTypeParameters == null && declaringType != null){
          if (declaringType.IsGeneric){
            if (declaringType.templateParameters == null) declaringType.templateParameters = new TypeNodeList(0);
            this.currentTypeParameters = declaringType.ConsolidatedTemplateParameters;
          }
          declaringType = declaringType.DeclaringType;
        }
        type.members = new MemberList();
        n = nestedClasses.Length;
        for (int i = 0; i < n; i++){
          NestedClassRow ncr = nestedClasses[i];
          if (ncr.EnclosingClass != typeTableIndex) continue;
          TypeNode t = this.GetTypeFromDef(ncr.NestedClass);
          if (t != null){
            t.DeclaringType = type;
            if ((t.Flags & TypeFlags.RTSpecialName) == 0 || t.Name.UniqueIdKey != StandardIds._Deleted.UniqueIdKey)
              type.Members.Add(t);
          }
        }
        n = typeDefs.Length;
        int m = fieldDefs.Length;
        int start = td.FieldList;
        int end = m+1; if (typeTableIndex < n) end = typeDefs[typeTableIndex].FieldList;
        if (type is EnumNode) this.GetUnderlyingTypeOfEnumNode((EnumNode)type, fieldDefs, fieldPtrs, start, end);
        this.AddFieldsToType(type, fieldDefs, fieldPtrs, start, end);
        m = methodDefs.Length;
        start = td.MethodList;
        end = m+1; if (typeTableIndex < n) end = typeDefs[typeTableIndex].MethodList;
        this.AddMethodsToType(type, methodPtrs, start, end);
        n = propertyMaps.Length;
        m = propertyDefs.Length;
        for (int i = 0; i < n; i++){ //TODO: binary search
          PropertyMapRow pm = propertyMaps[i];
          if (pm.Parent != typeTableIndex) continue;
          start = pm.PropertyList;
          end = m+1; if (i < n-1) end = propertyMaps[i+1].PropertyList;
          this.AddPropertiesToType(type, propertyDefs, propertyPtrs, start, end);
        }
        n = eventMaps.Length;
        m = eventDefs.Length;
        for (int i = 0; i < n; i++){ //TODO: binary search
          EventMapRow em = eventMaps[i];
          if (em.Parent != typeTableIndex) continue;
          start = em.EventList;
          end = m+1; if (i < n-1) end = eventMaps[i+1].EventList;
          this.AddEventsToType(type, eventDefs, eventPtrs, start, end);
        }
        n = methodImpls.Length;
        for (int i = 0; i < n; i++){ //TODO: binary search
          MethodImplRow mir = methodImpls[i];
          if (mir.Class != typeTableIndex) continue;
          Method implementer = this.GetMethodDefOrRef(mir.MethodBody);
          if (implementer == null) continue;
          MethodList implementedInterfaceMethods = implementer.ImplementedInterfaceMethods;
          if (implementedInterfaceMethods == null)
            implementedInterfaceMethods = implementer.ImplementedInterfaceMethods = new MethodList();
          TypeNodeList savedMethodTypeParameters = this.currentMethodTypeParameters;
          this.currentMethodTypeParameters = implementer.TemplateParameters;
          implementedInterfaceMethods.Add(this.GetMethodDefOrRef(mir.MethodDeclaration));
          this.currentMethodTypeParameters = savedMethodTypeParameters;
        }
        this.currentTypeParameters = savedCurrentTypeParameters;
#if !FxCop
      }catch(Exception e){
        if (this.module != null){
          if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
          this.module.MetadataImportErrors.Add(e);
        }
        type.Members = new MemberList(0);
      }
      finally{
        this.currentTypeParameters = savedCurrentTypeParameters;
        this.currentType = savedCurrentType;
      }
#else
      }finally{}
#endif
    }
    private void GetTypeAttributes(TypeNode/*!*/ type, object/*!*/ handle) {
      Debug.Assert(TypeNode.IsCompleteTemplate(type));
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      try{
        MetadataReader tables = this.tables;
        int typeTableIndex = (int)handle;
        TypeDefRow[] typeDefs = tables.TypeDefTable;
        int n = typeDefs.Length;
        if (typeTableIndex < 1 || typeTableIndex > n) 
          throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex);
        TypeDefRow td = typeDefs[typeTableIndex-1];
        if (type != td.Type) throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex);
        //Get custom attributes   
        type.Attributes = this.GetCustomAttributesNonNullFor((typeTableIndex << 5)|3);
        this.currentTypeParameters = savedCurrentTypeParameters;
        //Get security attributes
        if ((type.Flags & TypeFlags.HasSecurity) != 0)
          type.SecurityAttributes = this.GetSecurityAttributesFor((typeTableIndex << 2)|0);
#if !FxCop
      }catch(Exception e){
        if (this.module != null){
          if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
          this.module.MetadataImportErrors.Add(e);
        }
        type.Attributes = new AttributeList(0);
        this.currentTypeParameters = savedCurrentTypeParameters;
      }
#else
      }finally{}
#endif
    }
    private void GetTypeParameterAttributes(TypeNode/*!*/ type, object/*!*/ handle) {
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      try {
        MetadataReader tables = this.tables;
        int genericParamIndex = (int)handle;
        GenericParamRow[] genParDefs = tables.GenericParamTable;
        int n = genParDefs.Length;
        if (genericParamIndex < 1 || genericParamIndex > n)
          throw new System.ArgumentOutOfRangeException("handle", ExceptionStrings.InvalidTypeTableIndex);
        GenericParamRow td = genParDefs[genericParamIndex-1];
        //Get custom attributes   
        type.Attributes = this.GetCustomAttributesNonNullFor((genericParamIndex << 5)|19);
        this.currentTypeParameters = savedCurrentTypeParameters;
#if !FxCop
      } catch (Exception e) {
        if (this.module != null) {
          if (this.module.MetadataImportErrors == null) this.module.MetadataImportErrors = new ArrayList();
          this.module.MetadataImportErrors.Add(e);
        }
        type.Attributes = new AttributeList(0);
        this.currentTypeParameters = savedCurrentTypeParameters;
      }
#else
      }finally{}
#endif
    }
    private TypeNodeList/*!*/ ParseTypeList(MemoryCursor/*!*/ sigReader) {
      int n = sigReader.ReadCompressedInt();
      TypeNodeList result = new TypeNodeList(n);
      for (int i = 0; i < n; i++){
        TypeNode t = this.ParseTypeSignature(sigReader);
        if (t == null || t == Struct.Dummy){
          //Can happen when dealing with a primitive type that implements an interface that references the primitive type.
          //For example, System.String implements IComparable<System.String>.
          if (this.currentType != null && !CoreSystemTypes.Initialized)
            t = this.currentType;
          else{
            Debug.Assert(false);
            t = new TypeParameter();
            t.Name = Identifier.For("Bad type parameter in position "+i);
            t.DeclaringModule = this.module;
          }
        }
        result.Add(t);
      }
      return result;
    }
    private bool TypeSignatureIsClass(MemoryCursor/*!*/ sigReader) {
      ElementType tok = (ElementType)sigReader.ReadCompressedInt();
      switch(tok){
        case ElementType.Pinned:
        case ElementType.Pointer: 
        case ElementType.Reference: 
          return this.TypeSignatureIsClass(sigReader);
        case ElementType.OptionalModifier:
        case ElementType.RequiredModifier:
          sigReader.ReadCompressedInt();
          return this.TypeSignatureIsClass(sigReader);
        case ElementType.Class: 
          return true;// [maf] counter intuitive, but this is used to determine if a type parameter is constrained to be a class. If the type parameter derives from an interface type, then it is not constrained, but the interface type has that Elementtype Class
        case ElementType.GenericTypeInstance: 
          return this.TypeSignatureIsClass(sigReader);
        case ElementType.TypeParameter: {
            int pnum = sigReader.ReadCompressedInt();
            if (this.currentTypeParameters != null && this.currentTypeParameters.Count > pnum) {
              TypeNode tPar = this.currentTypeParameters[pnum];
              return tPar != null && tPar is Class;
            }
            return false;
          }
        case ElementType.MethodParameter: {
            int pnum = sigReader.ReadCompressedInt();
            if (this.currentMethodTypeParameters != null && this.currentMethodTypeParameters.Count > pnum) {
              TypeNode tPar = this.currentMethodTypeParameters[pnum];
              return tPar != null && tPar is Class;
            }
            return false;
          }
        default:
          return false;
      }
    }
    private TypeNode ParseTypeSignature(MemoryCursor/*!*/ sigReader) {
      bool junk = false;
      return this.ParseTypeSignature(sigReader, ref junk, ref junk);
    }
    private TypeNode ParseTypeSignature(MemoryCursor/*!*/ sigReader, ref bool pinned) {
      bool junk = false;
      return this.ParseTypeSignature(sigReader, ref pinned, ref junk);
    }
    private TypeNode ParseTypeSignature(MemoryCursor/*!*/ sigReader, ref bool pinned, ref bool isTypeArgument) {
      TypeNode elementType;
      ElementType tok = (ElementType)sigReader.ReadCompressedInt();
      if (tok == ElementType.Pinned){
        pinned = true;
        tok = (ElementType)sigReader.ReadCompressedInt();
      }
      switch(tok){
        case ElementType.Boolean: return CoreSystemTypes.Boolean;
        case ElementType.Char: return CoreSystemTypes.Char;
        case ElementType.Double: return CoreSystemTypes.Double;
        case ElementType.Int16: return CoreSystemTypes.Int16;
        case ElementType.Int32: return CoreSystemTypes.Int32;
        case ElementType.Int64: return CoreSystemTypes.Int64;
        case ElementType.Int8: return CoreSystemTypes.Int8;
        case ElementType.IntPtr: return CoreSystemTypes.IntPtr;
        case ElementType.BoxedEnum:
        case ElementType.Object: return CoreSystemTypes.Object;
        case ElementType.Single: return CoreSystemTypes.Single;
        case ElementType.String: return CoreSystemTypes.String;
        case ElementType.DynamicallyTypedReference : return CoreSystemTypes.DynamicallyTypedReference;
        case ElementType.UInt16: return CoreSystemTypes.UInt16;
        case ElementType.UInt32: return CoreSystemTypes.UInt32;
        case ElementType.UInt64: return CoreSystemTypes.UInt64;
        case ElementType.UInt8: return CoreSystemTypes.UInt8;
        case ElementType.UIntPtr: return CoreSystemTypes.UIntPtr;
        case ElementType.Void: return CoreSystemTypes.Void;
        case ElementType.Pointer:
          elementType = this.ParseTypeSignature(sigReader, ref pinned);
          if (elementType == null) elementType = CoreSystemTypes.Object;
          if (elementType == null) return null;
          return elementType.GetPointerType();
        case ElementType.Reference:
          elementType = this.ParseTypeSignature(sigReader, ref pinned);
          if (elementType == null) elementType = CoreSystemTypes.Object;
          return elementType.GetReferenceType();
        case ElementType.FunctionPointer:
          return this.ParseFunctionPointer(sigReader);
        case ElementType.OptionalModifier:
        case ElementType.RequiredModifier:
          TypeNode modifier = this.DecodeAndGetTypeDefOrRefOrSpec(sigReader.ReadCompressedInt());
          if (modifier == null) modifier = CoreSystemTypes.Object;
          TypeNode modified = this.ParseTypeSignature(sigReader, ref pinned);
          if (modified == null) modified = CoreSystemTypes.Object;
          if (modified == null || modified == null) return null;
          if (tok == ElementType.RequiredModifier)
            return RequiredModifier.For(modifier, modified);
          else
            return OptionalModifier.For(modifier, modified);
        case ElementType.Class:
          return this.DecodeAndGetTypeDefOrRefOrSpec(sigReader.ReadCompressedInt());
        case ElementType.ValueType:
          return this.DecodeAndGetTypeDefOrRefOrSpec(sigReader.ReadCompressedInt(), true);
        case ElementType.TypeParameter:
          TypeNode tPar = null;
          int pnum = sigReader.ReadCompressedInt();
          if (this.currentTypeParameters != null && this.currentTypeParameters.Count > pnum)
            tPar = this.currentTypeParameters[pnum];
          if (tPar == null){
            HandleError(this.module, String.Format(CultureInfo.CurrentCulture,
                ExceptionStrings.BadTypeParameterInPositionForType, pnum, this.currentType == null ? "" : this.currentType.FullName));
            tPar = new TypeParameter();
            tPar.Name = Identifier.For("Bad type parameter in position "+pnum);
            tPar.DeclaringModule = this.module;
          }
          isTypeArgument = true;
          return tPar;
        case ElementType.MethodParameter:
          TypeNode mTPar = null;
          pnum = sigReader.ReadCompressedInt();
          if (this.currentMethodTypeParameters != null && this.currentMethodTypeParameters.Count > pnum)
            mTPar = this.currentMethodTypeParameters[pnum];
          if (mTPar == null){
            HandleError(this.module, String.Format(CultureInfo.CurrentCulture,
                ExceptionStrings.BadMethodTypeParameterInPosition, pnum));
            mTPar = new MethodTypeParameter();
            mTPar.Name = Identifier.For("Bad method type parameter in position "+pnum);
          }
          isTypeArgument = true;
          return mTPar;
        case ElementType.GenericTypeInstance:
          TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
          TypeNode template = this.ParseTypeSignature(sigReader, ref pinned);
          this.currentTypeParameters = savedCurrentTypeParameters;
          if (template == null) return null;
          if (template.ConsolidatedTemplateParameters == null) {
            //The template could not be resolved, so we have a dummy type that has not yet been instantiated
            //Now that it is being instantiated we know how many template parameters it has, we can dummy up some template parameters
            template.IsGeneric = true;
            template.templateParameters = new TypeNodeList();
            for (int i = 0, n = sigReader.Byte(0); i < n; i++)
              template.templateParameters.Add(new TypeParameter());
          }
          if (CoreSystemTypes.Initialized){
            if (this.currentTypeParameters == null || this.currentTypeParameters.Count == 0)
              this.currentTypeParameters = template.ConsolidatedTemplateParameters;
            TypeNodeList genArgs = this.ParseTypeList(sigReader);
            if (this.module == null) return null;
            TypeNode genInst = template.GetGenericTemplateInstance(this.module, genArgs);
            this.currentTypeParameters = savedCurrentTypeParameters;
            return genInst;
          }
          InterfaceExpression ifaceExpr = new InterfaceExpression(null);
          ifaceExpr.Template = template;
          ifaceExpr.Namespace = template.Namespace;
          ifaceExpr.Name = template.Name;
          ifaceExpr.TemplateArguments = this.ParseTypeList(sigReader);
          this.currentTypeParameters = savedCurrentTypeParameters;
          return ifaceExpr;
        case ElementType.SzArray:
          elementType = this.ParseTypeSignature(sigReader, ref pinned);
          if (elementType == null) elementType = CoreSystemTypes.Object;
          if (elementType == null) return null;
          return elementType.GetArrayType(1);
        case ElementType.Array:
          elementType = this.ParseTypeSignature(sigReader, ref pinned);
          if (elementType == null) elementType = CoreSystemTypes.Object;
          if (elementType == null) return null;
          int rank = sigReader.ReadCompressedInt();
          int numSizes = sigReader.ReadCompressedInt();
          int[] sizes = new int[numSizes];
          for (int i = 0; i < numSizes; i++) sizes[i] = sigReader.ReadCompressedInt();
          int numLoBounds = sigReader.ReadCompressedInt();
          int[] loBounds = new int[numLoBounds];
          for (int i = 0; i < numLoBounds; i++) loBounds[i] = sigReader.ReadCompressedInt();
          return elementType.GetArrayType(rank, numSizes, numLoBounds, sizes, loBounds);
        case ElementType.Sentinel: return null;
        case ElementType.Type: return CoreSystemTypes.Type;
        case ElementType.Enum: return this.GetTypeFromSerializedName(ReadSerString(sigReader));
      }
      throw new InvalidMetadataException(ExceptionStrings.MalformedSignature);
    }
    private FunctionPointer/*!*/ ParseFunctionPointer(MemoryCursor/*!*/ sigReader) {
      CallingConventionFlags convention = (CallingConventionFlags)sigReader.ReadByte();
      int n = sigReader.ReadCompressedInt();
      TypeNode returnType = this.ParseTypeSignature(sigReader);
      if (returnType == null) returnType = CoreSystemTypes.Object;
      TypeNodeList parameterTypes = new TypeNodeList(n);
      int m = n;
      for (int i = 0; i < n; i++){
        TypeNode t = this.ParseTypeSignature(sigReader);
        if (t == null)
          m = i--;
        else
          parameterTypes.Add(t);
      }
      FunctionPointer fp = FunctionPointer.For(parameterTypes, returnType);
      fp.CallingConvention = convention;
      fp.VarArgStart = m;
      return fp;
    }
    private StatementList ParseMethodBody(Method/*!*/ method, int methodIndex, int RVA) {
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      if (method.DeclaringType.Template != null)
        this.currentTypeParameters = method.DeclaringType.ConsolidatedTemplateArguments;
      else
        this.currentTypeParameters = method.DeclaringType.ConsolidatedTemplateParameters;
      BodyParser parser = new BodyParser(this, method, methodIndex, RVA);
      StatementList result = parser.ParseStatements();
      this.currentTypeParameters = savedCurrentTypeParameters;
      return result;
    }
    private InstructionList ParseMethodInstructions(Method/*!*/ method, int methodIndex, int RVA) {
      TypeNodeList savedCurrentTypeParameters = this.currentTypeParameters;
      if (method.DeclaringType.Template != null)
        this.currentTypeParameters = method.DeclaringType.ConsolidatedTemplateArguments;
      else
        this.currentTypeParameters = method.DeclaringType.ConsolidatedTemplateParameters;
      InstructionParser parser = new InstructionParser(this, method, methodIndex, RVA);
      InstructionList result = parser.ParseInstructions();
      this.currentTypeParameters = savedCurrentTypeParameters;
      return result;
    }
  }

  internal struct LocalInfo
  {
    public LocalInfo(string name, uint attributes)
    {
      this.Name = name;
      this.Attributes = attributes;
    }
    public readonly string Name;
    public readonly uint Attributes;
  }

  public class SerializedTypeName {
    private readonly StringList names = new StringList();
    private string assembly = string.Empty;
    private readonly SerializedTypeNameList genericArguments = new SerializedTypeNameList();
    private bool isGenericArgument;
    private readonly Int32List signature = new Int32List();
    public StringList Names {
      get { return this.names; }
    }
    public string Assembly {
      get { return this.assembly; }
    }
    public SerializedTypeNameList GenericArguments {
      get { return this.genericArguments; }
    }
    public bool IsGenericArgument {
      get { return this.isGenericArgument; }
    }
    private SerializedTypeName() {
    }
    public static bool TryParse(string typeNameString, out SerializedTypeName typeName) {
      typeName = new SerializedTypeName();
      return TypeNameParser.TryParse(typeNameString, typeName);
    }
    private SerializedTypeName AddGenericArgument() {
      SerializedTypeName genArg = new SerializedTypeName {isGenericArgument = true};
      this.genericArguments.Add(genArg);
      return genArg;
    }
    private const int ByRefSignature = -1;
    private const int PointerSignature = -2;
    private const int SzArraySignature = -3;
    private void SetByRef() {
      this.signature.Add(ByRefSignature);
    }
    private void SetPointer() {
      this.signature.Add(PointerSignature);
    }
    private void SetSzArray() {
      this.signature.Add(SzArraySignature);
    }
    private void SetArray(int rank) {
      if (rank < 1) throw new ArgumentOutOfRangeException("rank");
      this.signature.Add(rank);
    }
    public TypeNode ApplySignature(TypeNode type) {
      foreach (var sig in this.signature)
        switch (sig) {
          case ByRefSignature:
            type = type.GetReferenceType();
            break;
          case PointerSignature:
            type = type.GetPointerType();
            break;
          case SzArraySignature:
            type = type.GetArrayType(1);
            break;
          default:
            type = type.GetArrayType(sig, true);
            break;
        }
      return type;
    }
    private class TypeNameParser {
      private SerializedTypeName typeName;
      private readonly string typeNameString;
      private int itr;
      private int currentItr;
      private TypeNameTokens currentToken;
      private TypeNameTokens nextToken;
      private TypeNameParser(string typeNameString, SerializedTypeName typeName) {
        if (typeNameString == null)
          typeNameString = string.Empty;
        this.currentToken = TypeNameTokens.Empty;
        this.nextToken = TypeNameTokens.Empty;
        this.typeName = typeName;
        this.typeNameString = typeNameString;
        this.currentItr = this.itr = 0;
      }
      public static bool TryParse(string typeNameString, SerializedTypeName typeName) {
        var parser = new TypeNameParser(typeNameString, typeName);
        return parser.Start();
      }
      private void NextToken() {
        this.currentToken = this.nextToken;
        this.currentItr = this.itr;
        this.nextToken = this.LexAToken();
      }
      private bool NextTokenIs(TypeNameTokens token) {
        return (this.nextToken & token) != 0;
      }
      private bool TokenIs(TypeNameTokens token) {
        return (this.currentToken & token) != 0;
      }
      private bool IsTypeNameReservedChar(char ch) {
        switch (ch) {
          case ',':
          case '[':
          case ']':
          case '&':
          case '*':
          case '+':
          case '\\':
            return true;
          default:
            return false;
        }
      }
      private TypeNameTokens LexAToken() {
        do {
          if (this.nextToken == TypeNameTokens.Identifier)
            return TypeNameTokens.PostIdentifier;
          if (this.nextToken == TypeNameTokens.End)
            return TypeNameTokens.End;
          if (this.itr >= this.typeNameString.Length)
            return TypeNameTokens.End;
          if (char.IsWhiteSpace(this.typeNameString[this.itr])) {
            this.itr++;
            continue;
          }
          char c = this.typeNameString[this.itr];
          this.itr++;
          switch (c) {
            case ',':
              return TypeNameTokens.Comma;
            case '[':
              return TypeNameTokens.OpenSqBracket;
            case ']':
              return TypeNameTokens.CloseSqBracket;
            case '&':
              return TypeNameTokens.Amperstand;
            case '*':
              return TypeNameTokens.Astrix;
            case '+':
              return TypeNameTokens.Plus;
            case '\\':
              this.itr--;
              return TypeNameTokens.Identifier;
          }
          this.itr--;
          return TypeNameTokens.Identifier;
        } while (true);
      }
      private string GetIdentifier(TypeNameIdentifiers identifierType) {
        int start = this.currentItr;
        Int32List escape = new Int32List();
        if (identifierType == TypeNameIdentifiers.Id) {
          do {
            char c = this.currentItr < this.typeNameString.Length ? this.typeNameString[this.currentItr] : '\0';
            this.currentItr++;
            switch (c) {
              case ',':
              case '[':
              case ']':
              case '&':
              case '*':
              case '+':
              case '\0':
                goto done;
              case '\\':
                escape.Add(this.currentItr - 1);
                if (!this.IsTypeNameReservedChar(this.typeNameString[this.currentItr]) || this.currentItr >= this.typeNameString.Length)
                  return null;
                this.currentItr++;
                break;
            }
          } while (true);
          done:
          this.currentItr--;
        } else if (identifierType == TypeNameIdentifiers.FusionName)
          this.currentItr = this.typeNameString.Length;
        else if (identifierType == TypeNameIdentifiers.EmbeddedFusionName) {
          for (; (this.currentItr < this.typeNameString.Length) && (this.typeNameString[this.currentItr] != ']'); this.currentItr++) {
            if (this.typeNameString[this.currentItr] == '\\')
              if (this.typeNameString[this.currentItr + 1] == ']') {
                escape.Add(this.currentItr);
                this.currentItr++;
                continue;
              }
            if (this.currentItr >= this.typeNameString.Length)
              return null;
          }
          if (this.currentItr >= this.typeNameString.Length)
            return null;
        } else
          return null;
        this.itr = this.currentItr;
        this.nextToken = this.LexAToken();
        if (escape.Count < 1)
          return this.typeNameString.Substring(start, this.currentItr - start);
        Text.StringBuilder idBuilder = new Text.StringBuilder(this.currentItr - start - escape.Count);
        int s = start;
        for (int i = 0; i < escape.Count; i++) {
          int e = escape[i];
          idBuilder.Append(this.typeNameString, s, e - s);
          s = e + 1;
        }
        if (s < this.typeNameString.Length)
          idBuilder.Append(this.typeNameString, s, this.currentItr - s);
        return idBuilder.ToString();
      }
      private bool Start() {
        this.NextToken();
        this.NextToken();
        return this.AQN();
      }
      private bool AQN() {
        if (!this.TokenIs(TypeNameTokens.AQN)) return false;
        if (this.TokenIs(TypeNameTokens.End)) return true;
        if (!this.FullName()) return false;
        if (this.TokenIs(TypeNameTokens.Comma)) {
          this.NextToken();
          if (!this.AssemSpec()) return false;
        }
        if (!this.TokenIs(TypeNameTokens.End)) return false;
        return true;
      }
      private bool AssemSpec() {
        if (!this.TokenIs(TypeNameTokens.AssemSpec)) return false;
        string assembly = this.GetIdentifier(TypeNameIdentifiers.FusionName);
        if (assembly != null) this.typeName.assembly = assembly;
        this.NextToken();
        return true;
      }
      private bool FullName() {
        if (!this.TokenIs(TypeNameTokens.FullName)) return false;
        if (!this.Name()) return false;
        if (!this.GenParams()) return false;
        if (!this.Qualifier()) return false;
        return true;
      }
      private bool GenParams() {
        if (!this.TokenIs(TypeNameTokens.GenParam))
          return true;
        if (!this.NextTokenIs(TypeNameTokens.GenArgs))
          return true;
        this.NextToken();
        if (!this.GenArgs()) return false;
        if (!this.TokenIs(TypeNameTokens.CloseSqBracket)) return false;
        this.NextToken();
        return true;
      }
      private bool GenArgs() {
        while (true) {
          if (!this.TokenIs(TypeNameTokens.GenArgs)) return false;
          if (!this.GenArg()) return false;
          if (!this.TokenIs(TypeNameTokens.Comma)) return true;
          this.NextToken();
        }
      }
      private bool GenArg() {
        SerializedTypeName enclosingTypeName = this.typeName;
        this.typeName = this.typeName.AddGenericArgument();
        if (this.TokenIs(TypeNameTokens.OpenSqBracket)) {
          this.NextToken();
          if (!this.EAQN()) return false;
          if (!this.TokenIs(TypeNameTokens.CloseSqBracket)) return false;
          this.NextToken();
        } else if (!this.FullName()) return false;
        this.typeName = enclosingTypeName;
        return true;
      }
      private bool EAQN() {
        if (!this.TokenIs(TypeNameTokens.EAQN)) return false;
        if (!this.FullName()) return false;
        if (this.TokenIs(TypeNameTokens.Comma)) {
          this.NextToken();
          if (!this.EAssemSpec()) return false;
        }
        return true;
      }
      private bool EAssemSpec() {
        if (!this.TokenIs(TypeNameTokens.EAssemSpec)) return false;
        string assembly = this.GetIdentifier(TypeNameIdentifiers.EmbeddedFusionName);
        if (assembly != null) this.typeName.assembly = assembly;
        this.NextToken();
        return true;
      }
      private bool Qualifier() {
        while (this.TokenIs(TypeNameTokens.Qualifier)) {
          if (this.TokenIs(TypeNameTokens.Amperstand)) {
            this.typeName.SetByRef();
            this.NextToken();
            return true;
          }
          if (this.TokenIs(TypeNameTokens.Astrix)) {
            this.typeName.SetPointer();
            this.NextToken();
          } else if (!this.Array()) return false;
        }
        return true;
      }
      private bool Array() {
        if (!this.TokenIs(TypeNameTokens.Array)) return false;
        this.NextToken();
        if (this.TokenIs(TypeNameTokens.Astrix)) {
          this.typeName.SetArray(1);
          this.NextToken();
        } else {
          int rank = 1;
          if (!this.Rank(ref rank)) return false;
          if (rank == 1)
            this.typeName.SetSzArray();
          else
            this.typeName.SetArray(rank);
        }
        if (!this.TokenIs(TypeNameTokens.CloseSqBracket)) return false;
        this.NextToken();
        return true;
      }
      private bool Rank(ref int rank) {
        while (this.TokenIs(TypeNameTokens.Rank)) {
          rank++;
          this.NextToken();
        }
        return true;
      }
      private bool Name() {
        if (!this.TokenIs(TypeNameTokens.Name)) return false;
        string name = this.GetIdentifier(TypeNameIdentifiers.Id);
        if (name != null) this.typeName.names.Add(name);
        this.NextToken();
        if (this.TokenIs(TypeNameTokens.Plus)) {
          do {
            this.NextToken();
            if (!this.TokenIs(TypeNameTokens.NestName)) return false;
            name = this.GetIdentifier(TypeNameIdentifiers.Id);
            if (name != null) this.typeName.names.Add(name);
            this.NextToken();
          } while (this.TokenIs(TypeNameTokens.Plus));
        }
        return true;
      }
    }
    [Flags]
    private enum TypeNameTokens : ushort {
      //
      // TOKENS
      //
      Empty = 0x8000,
      Identifier = 0x0001,
      PostIdentifier = 0x0002,
      OpenSqBracket = 0x0004,
      CloseSqBracket = 0x0008,
      Comma = 0x0010,
      Plus = 0x0020,
      Astrix = 0x0040,
      Amperstand = 0x0080,
      End = 0x4000,

      //
      // 1 TOKEN LOOK AHEAD
      //
      Name = Identifier,
      NestName = Identifier,
      AssemSpec = Identifier,
      GenParam = OpenSqBracket | Empty,
      FullName = Name,
      AQN = FullName | End,
      GenArg = OpenSqBracket | FullName,
      GenArgs = GenArg,
      EAQN = Identifier,
      EAssemSpec = Identifier,
      Array = OpenSqBracket,
      Qualifier = Amperstand | Astrix | Array | Empty,
      Rank = Comma | Empty,
    }
    [Flags]
    private enum TypeNameIdentifiers : byte {
      None = 0x00,
      Id = 0x01,
      FusionName = 0x02,
      EmbeddedFusionName = 0x03,
    }
  }

  internal abstract class ILParser{
    internal int counter;
    protected Reader/*!*/ reader;
    protected MemoryCursor/*!*/ bodyReader;
    internal int size;
    protected Method/*!*/ method;
    protected int methodIndex;
    protected int RVA;
    protected LocalList/*!*/ locals = new LocalList();

    internal ILParser(Reader/*!*/ reader, Method/*!*/ method, int methodIndex, int RVA) {
      this.reader = reader;
      this.bodyReader = reader.tables.GetNewCursor();
      this.method = method;
#if !FxCop
      this.method.LocalList = this.locals;
#else
      this.method.Locals = this.locals;
#endif
      this.methodIndex = methodIndex;
      this.RVA = RVA;
      //^ base();
    }
    protected Expression Parameters(int i){
      if (this.method.IsStatic) return this.method.Parameters[i];
      if (i == 0) return this.method.ThisParameter;
      return this.method.Parameters[i-1];
    }
    protected void ParseHeader(){
      byte header = this.reader.tables.GetMethodBodyHeaderByte(this.RVA);
      if ((header & 0x3) == 2){
        this.size = header >> 2;
        this.bodyReader = this.reader.tables.GetNewCursor();
        this.reader.tables.Skip(size);
      }else{    
        method.InitLocals = (header & 0x10) != 0;
        byte header2 = this.reader.tables.GetByte();
        int fatHeaderSize = header2 >> 4;
        if (fatHeaderSize == 2) return;
        if (fatHeaderSize != 3) throw new InvalidMetadataException(ExceptionStrings.InvalidFatMethodHeader);
        this.reader.tables.Skip(2); //Skip over maxstack. No need to remember it.
        this.size = this.reader.tables.GetInt32();
        int localIndex = this.reader.tables.GetInt32();
        this.bodyReader = this.reader.tables.GetNewCursor();
        this.reader.tables.Skip(size);
        this.reader.tables.AlignTo32BitBoundary();
        while ((header & 0x8) != 0){
          header = this.reader.tables.GetByte();
          if ((header & 3) != 1) throw new InvalidMetadataException(ExceptionStrings.BadMethodHeaderSection);
          if ((header & 0x80) != 0) throw new InvalidMetadataException(ExceptionStrings.TooManyMethodHeaderSections);
          this.ParseExceptionHandlerEntry((header & 0x40) == 0);
        }
        var localSourceNames = new System.Collections.Generic.Dictionary<int,LocalInfo>();
#if UseSingularityPDB
        if (this.reader.getDebugSymbols && this.reader.pdbFunctions != null) {
          PdbFunction pdbFunc = this.reader.GetPdbFunction(0x6000000|(uint)methodIndex);
          if (pdbFunc != null)
            this.GetLocalNames(pdbFunc.scopes, localSourceNames);
        }
#elif !ROTOR
        if (this.reader.getDebugSymbols && this.reader.debugReader != null){
          ISymUnmanagedMethod methodInfo = null;
          try{
            try{
              this.reader.debugReader.GetMethod(0x6000000|(uint)methodIndex, ref methodInfo);
              if (methodInfo != null){
                ISymUnmanagedScope rootScope = methodInfo.GetRootScope();
                try{
                  this.reader.GetLocalSourceNames(rootScope, localSourceNames);
#if CodeContracts
                  method.ExtraDebugInfo = ExtraPDBInfo.Parse(methodInfo.GetToken(), method, this.reader.debugReader, this.reader);
#endif
                }
                finally{
                  if (rootScope != null)
                    Marshal.ReleaseComObject(rootScope);
                }
              }
            }
            catch (COMException){
            }
            catch (InvalidCastException){
            }
            catch (System.Runtime.InteropServices.InvalidComObjectException){}            
          }
          finally{
            if (methodInfo != null)
              Marshal.ReleaseComObject(methodInfo);
          }
        }
#endif
        this.reader.GetLocals(localIndex, this.locals, localSourceNames);
      }
    }

#if UseSingularityPDB
    private void GetLocalNames(PdbScope[] scopes, Hashtable localSourceNames) {
      for (int i = 0, n = scopes == null ? 0 : scopes.Length; i < n; i++) {
        PdbScope scope = scopes[i];
        foreach (PdbSlot slot in scope.slots)
          localSourceNames[(int)slot.slot] = slot.name;
        this.GetLocalNames(scope.scopes, localSourceNames);
      }
    }
#endif


    abstract protected void ParseExceptionHandlerEntry(bool smallSection);
    protected byte GetByte(){
      this.counter += 1;
      return this.bodyReader.ReadByte();
    }
    protected sbyte GetSByte(){
      this.counter += 1;
      return this.bodyReader.ReadSByte();
    }
    protected short GetInt16(){
      this.counter += 2;
      return this.bodyReader.ReadInt16();
    }
    protected int GetInt32(){
      this.counter += 4;
      return this.bodyReader.ReadInt32();
    }
    protected long GetInt64(){
      this.counter += 8;
      return this.bodyReader.ReadInt64();
    }
    protected float GetSingle(){
      this.counter += 4;
      return this.bodyReader.ReadSingle();
    }
    protected double GetDouble(){
      this.counter += 8;
      return this.bodyReader.ReadDouble();
    }
    protected Member/*!*/ GetMemberFromToken(object memberInfo = null){
      return this.reader.GetMemberFromToken(this.GetInt32(), memberInfo);
    }
    protected Member/*!*/ GetMemberFromToken(out TypeNodeList varArgTypes) {
      return this.reader.GetMemberFromToken(this.GetInt32(), out varArgTypes);
    }
    protected string/*!*/ GetStringFromToken() {
      int tok = this.GetInt32();
      return this.reader.tables.GetUserString(tok & 0xFFFFFF);
    }
    protected OpCode GetOpCode(){
      int result = this.GetByte();
      if (result == (int)OpCode.Prefix1)
        result = result << 8 | this.GetByte();
      return (OpCode)result;
    }
  }
  sealed internal class BodyParser : ILParser{
    private readonly ExpressionStack/*!*/ operandStack = new ExpressionStack();
    private readonly TrivialHashtable/*!*/ blockMap = new TrivialHashtable(32);
    private int alignment = -1;
    private bool isReadOnly;
    private bool isTailCall;
    private bool isVolatile;
    private TypeNode constraint;

    internal BodyParser(Reader/*!*/ reader, Method/*!*/ method, int methodIndex, int RVA)
      : base(reader, method, methodIndex, RVA){
      //^ base;
    }
#if !FxCop
    override protected void ParseExceptionHandlerEntry(bool smallSection){
      int dataSize = this.reader.tables.GetByte();
      int n = (int)(ushort)this.reader.tables.GetInt16();
      if (smallSection)
        n = dataSize / 12;
      else
        n = (dataSize + (n << 8)) / 24;
      if (n < 0) n = 0;
      this.method.ExceptionHandlers = new ExceptionHandlerList(n);
      for (int i = 0; i < n; i++){
        int flags, tryOffset, tryLength, handlerOffset, handlerLength, tokenOrOffset;
        if (smallSection){
          flags = this.reader.tables.GetInt16();
          tryOffset = this.reader.tables.GetUInt16();
          tryLength = this.reader.tables.GetByte();
          handlerOffset = this.reader.tables.GetUInt16();
          handlerLength = this.reader.tables.GetByte();
        }else{
          flags = this.reader.tables.GetInt32();
          tryOffset = this.reader.tables.GetInt32();
          tryLength = this.reader.tables.GetInt32();
          handlerOffset = this.reader.tables.GetInt32();
          handlerLength = this.reader.tables.GetInt32();
        }
        tokenOrOffset = this.reader.tables.GetInt32();
        ExceptionHandler eh = new ExceptionHandler();
        switch(flags){
          case 0x00: 
            eh.HandlerType = NodeType.Catch;
            int pos = this.reader.tables.GetCurrentPosition();
            eh.FilterType = (TypeNode)this.reader.GetMemberFromToken(tokenOrOffset);
            this.reader.tables.SetCurrentPosition(pos);
            break;
          case 0x01: 
            eh.HandlerType = NodeType.Filter; 
            eh.FilterExpression = Reader.GetOrCreateBlock(blockMap, tokenOrOffset);
            break;
          case 0x02: eh.HandlerType = NodeType.Finally; break;
          case 0x04: eh.HandlerType = NodeType.FaultHandler; break;
          default: throw new InvalidMetadataException(ExceptionStrings.BadExceptionHandlerType);
        }
        eh.TryStartBlock = Reader.GetOrCreateBlock(this.blockMap, tryOffset);
        eh.BlockAfterTryEnd = Reader.GetOrCreateBlock(this.blockMap, tryOffset+tryLength);
        eh.HandlerStartBlock = Reader.GetOrCreateBlock(this.blockMap, handlerOffset);
        eh.BlockAfterHandlerEnd = Reader.GetOrCreateBlock(this.blockMap, handlerOffset+handlerLength);
        this.method.ExceptionHandlers.Add(eh);
      }
    }
#endif
    private AssignmentStatement/*!*/ ParseArrayElementAssignment(OpCode opCode) {
      Expression rhvalue = PopOperand();
      ExpressionList indexers = new ExpressionList(1);
      indexers.Add(PopOperand());
      Expression array = PopOperand();
      Indexer indexer = new Indexer(array, indexers);
      TypeNode t = CoreSystemTypes.Object;
      switch(opCode){
        case OpCode.Stelem_I: t = CoreSystemTypes.IntPtr; break;
        case OpCode.Stelem_I1: t = CoreSystemTypes.Int8; break;
        case OpCode.Stelem_I2: t = CoreSystemTypes.Int16; break;
        case OpCode.Stelem_I4: t = CoreSystemTypes.Int32; break;
        case OpCode.Stelem_I8: t = CoreSystemTypes.Int64; break;
        case OpCode.Stelem_R4: t = CoreSystemTypes.Single; break;
        case OpCode.Stelem_R8: t = CoreSystemTypes.Double; break;
        case OpCode.Stelem: t = (TypeNode)this.GetMemberFromToken(); break;
        default:
          ArrayType arrT = array.Type as ArrayType;
          if (arrT != null) t = arrT.ElementType;
          break;
      }
      indexer.ElementType = indexer.Type = t;
      return new AssignmentStatement(indexer, rhvalue);
    }
    private Indexer/*!*/ ParseArrayElementLoad(OpCode opCode, TypeNode elementType){
      ExpressionList indexers = new ExpressionList(1); indexers.Add(PopOperand());
      Expression array = PopOperand();
      Indexer indexer = new Indexer(array, indexers);
      TypeNode t = elementType;
      switch(opCode){
        case OpCode.Ldelem_I1: t = CoreSystemTypes.Int8; break;
        case OpCode.Ldelem_U1: t = CoreSystemTypes.UInt8; break;
        case OpCode.Ldelem_I2: t = CoreSystemTypes.Int16; break;
        case OpCode.Ldelem_U2: t = CoreSystemTypes.UInt16; break;
        case OpCode.Ldelem_I4: t = CoreSystemTypes.Int32; break;
        case OpCode.Ldelem_U4: t = CoreSystemTypes.UInt32; break;
        case OpCode.Ldelem_I8: t = CoreSystemTypes.Int64; break;
        case OpCode.Ldelem_I: t = CoreSystemTypes.IntPtr; break;
        case OpCode.Ldelem_R4: t = CoreSystemTypes.Single; break;
        case OpCode.Ldelem_R8: t = CoreSystemTypes.Double; break;
        case OpCode.Ldelem: t = (TypeNode)this.GetMemberFromToken(); break;
        default:
          if (t != null) break;
          t = CoreSystemTypes.Object;
          ArrayType arrT = array.Type as ArrayType;
          if (arrT != null) t = arrT.ElementType;
          break;
      }
      indexer.ElementType = indexer.Type = t;
      return indexer;
    }
    private UnaryExpression/*!*/ ParseArrayElementLoadAddress() {
      TypeNode elemType = (TypeNode)this.GetMemberFromToken();
      return new UnaryExpression(this.ParseArrayElementLoad(0, elemType), this.isReadOnly ? NodeType.ReadOnlyAddressOf : NodeType.AddressOf, elemType.GetReferenceType());
    }
    private static UnaryExpression/*!*/ SetType(UnaryExpression/*!*/ uex) {
      if (uex == null || uex.Operand == null) return uex;
      TypeNode elemType = uex.Operand.Type;
      if (elemType == null) return uex;
      uex.Type = elemType.GetReferenceType();
      return uex;
    }
    private BinaryExpression/*!*/ ParseBinaryComparison(NodeType oper) {
      Expression op2 = PopOperand();
      Expression op1 = PopOperand();
      BinaryExpression result = new BinaryExpression(op1, op2, oper);
      result.Type = CoreSystemTypes.Int32;
      return result;
    }
    private BinaryExpression/*!*/ ParseBinaryOperation(NodeType oper) {
      Expression op2 = PopOperand();
      Expression op1 = PopOperand();
      BinaryExpression result = new BinaryExpression(op1, op2, oper);
      result.Type = op1.Type;
      if (result.Type == null) result.Type = op2.Type;
      return result;
    }
    private UnaryExpression/*!*/ ParseUnaryOperation(NodeType oper) {
      Expression op = PopOperand();
      return new UnaryExpression(op, oper, op.Type);
    }
    private Branch/*!*/ ParseBranch(NodeType operatorType, int operandCount, bool shortOffset, bool unordered) {
      return this.ParseBranch(operatorType, operandCount, shortOffset, unordered, false);
    }
    private Branch/*!*/ ParseBranch(NodeType operatorType, int operandCount, bool shortOffset, bool unordered, bool leavesExceptionBlock) {
      Expression operand2 = operandCount > 1 ? PopOperand() : null;
      Expression operand1 = operandCount > 0 ? PopOperand() : null;
      Expression condition = operandCount > 1 ? (Expression)new BinaryExpression(operand1, operand2, operatorType) :
        (operandCount > 0 ? (operatorType == NodeType.Nop ? operand1 : (Expression)new UnaryExpression(operand1, operatorType)) : null);
      int targetAddress = shortOffset ? this.GetSByte() : this.GetInt32();
      Block targetBlock = (Block)this.blockMap[targetAddress+this.counter+1];
      Debug.Assert(targetBlock != null);
      if (targetAddress >= 0 && !this.reader.preserveShortBranches) shortOffset = false;
      return new Branch(condition, targetBlock, shortOffset, unordered, leavesExceptionBlock);
    }
    private MethodCall/*!*/ ParseCall(NodeType typeOfCall, out bool isStatement) {
      TypeNodeList varArgTypes;
      Method meth = (Method)this.GetMemberFromToken(out varArgTypes);
      int numVarArgs = varArgTypes == null ? 0 : varArgTypes.Count;
      isStatement = BodyParser.TypeIsVoid(meth.ReturnType);
      int n = meth.Parameters == null ? 0 : meth.Parameters.Count; 
      if (typeOfCall == NodeType.Jmp) n = 0;
      else n += numVarArgs;
      Expression[] args = new Expression[n];
      ExpressionList arguments = new ExpressionList(n);
      for (int i = n-1; i >= 0; i--) args[i] = PopOperand();
      for (int i = 0; i < n; i++) arguments.Add(args[i]);
      if (varArgTypes != null) {
        for (int i = n-1, j = numVarArgs; j > 0; j--, i--) {
          Expression e = arguments[i];
          TypeNode t = varArgTypes[j-1];
          if (e != null && t != null) e.Type = t;
        }
      }
      Expression thisob = meth.IsStatic ? null : PopOperand();
      MemberBinding methBinding = new MemberBinding(thisob, meth);
      MethodCall result = new MethodCall(methBinding, arguments, typeOfCall);
      result.Type = meth.ReturnType;
      result.IsTailCall = this.isTailCall;
      if (this.constraint != null){
        result.Constraint = this.constraint;
        this.constraint = null;
      }
      return result;
    }
    private static bool TypeIsVoid(TypeNode t){
      if (t == null) return false;
      for(;;){
        switch(t.NodeType){
          case NodeType.OptionalModifier:
          case NodeType.RequiredModifier:
            t = ((TypeModifier)t).ModifiedType;
            break;
          default:
            return t == CoreSystemTypes.Void;
        }
      }
    }
    private MethodCall/*!*/ ParseCalli(out bool isStatement) {
      FunctionPointer fp = this.reader.GetCalliSignature(this.GetInt32());
      if (fp == null) throw new InvalidMetadataException(ExceptionStrings.BaddCalliSignature);
      isStatement = BodyParser.TypeIsVoid(fp.ReturnType);
      int n = fp.ParameterTypes.Count; 
      Expression[] args = new Expression[n+1];
      ExpressionList arguments = new ExpressionList(n+1);
      for (int i = n; i >= 0; i--) args[i] = PopOperand();
      for (int i = 0; i <= n; i++) arguments.Add(args[i]);
      Expression thisob = fp.IsStatic ? null : PopOperand();
      MemberBinding methBinding = new MemberBinding(thisob, fp);
      MethodCall result = new MethodCall(methBinding, arguments, NodeType.Calli);
      result.Type = fp.ReturnType;
      result.IsTailCall = this.isTailCall;
      return result;
    }
    private static Expression/*!*/ ParseTypeCheck(Expression operand, TypeNode type, NodeType typeOfCheck) {
      TypeNode etype = type;
      if (typeOfCheck == NodeType.Unbox) etype = type.GetReferenceType();
      Expression expr = new BinaryExpression(operand, new Literal(type, CoreSystemTypes.Type), typeOfCheck, etype);
      return expr;
    }
    private Construct/*!*/ ParseConstruct() {
      TypeNodeList varArgTypes;
      Method meth = (Method)this.GetMemberFromToken(out varArgTypes);
      int n = meth.Parameters.Count;
      Expression[] args = new Expression[n];
      ExpressionList arguments = new ExpressionList(n);
      for (int i = n-1; i >= 0; i--) args[i] = PopOperand();
      for (int i = 0; i < n; i++) arguments.Add(args[i]);
      Construct result = new Construct(new MemberBinding(null, meth), arguments);
      result.Type = meth.DeclaringType;
      return result;
    }
    private AssignmentStatement/*!*/ ParseCopyObject() {
      TypeNode type = (TypeNode)this.GetMemberFromToken();
      Expression rhaddr = PopOperand();
      Expression lhaddr = PopOperand();
      return new AssignmentStatement(new AddressDereference(lhaddr, type, this.isVolatile, this.alignment), new AddressDereference(rhaddr, type));
    }
    private UnaryExpression /*!*/ ParseLoadRuntimeMetadataToken() {
      Expression expr = null;
      TypeNode exprType = null;
      Member member = this.GetMemberFromToken();
      TypeNode t = member as TypeNode;
      if (t == null) {
        exprType = (member.NodeType == NodeType.Field)
          ? CoreSystemTypes.RuntimeFieldHandle : CoreSystemTypes.RuntimeMethodHandle;
        expr = new MemberBinding(null, member);
      } else {
        exprType = CoreSystemTypes.RuntimeTypeHandle;
        expr = new Literal(t, CoreSystemTypes.Type);
      }
      return new UnaryExpression(expr, NodeType.Ldtoken, exprType);
    }
    private AssignmentStatement/*!*/ ParseInitObject() {
      TypeNode type = (TypeNode)this.GetMemberFromToken();
      Expression lhaddr = PopOperand();
      return new AssignmentStatement(new AddressDereference(lhaddr, type, this.isVolatile, this.alignment), new Literal(null, CoreSystemTypes.Object));
    }
    private ConstructArray/*!*/ ParseNewArray() {
      TypeNode type = (TypeNode)this.GetMemberFromToken();
      ExpressionList sizes = new ExpressionList(1);
      sizes.Add(PopOperand());
      ConstructArray result = new ConstructArray(type, sizes, null);
      result.Type = type.GetArrayType(1);
      return result;
    }
#if !FxCop
    internal StatementList/*!*/ ParseStatements() {
      this.ParseHeader();
      if (this.size == 0) return new StatementList(0);
      this.CreateBlocksForBranchTargets();
      StatementList result = new StatementList();
      Block currentBlock = null;
      while (this.counter < size){
        if (currentBlock == null){
          currentBlock = Reader.GetOrCreateBlock(this.blockMap, this.counter);
#if ILOFFSETS
          currentBlock.SourceContext = lastSourceContext;
#endif
          result.Add(currentBlock);
        }
        bool endOfBasicBlock = this.ParseStatement(currentBlock);
        if (endOfBasicBlock) currentBlock = null;
      }
      result.Add(Reader.GetOrCreateBlock(this.blockMap, this.counter));
      return result;
    }
#endif
    private bool ParseStatement(Block/*!*/ block) {
      //parse instructions and put in expression tree until an assignment, void call, branch target, or branch is encountered
      StatementList statementList = block.Statements;
      Expression expr = null;
      Statement statement = null;
      bool transferStatement = false;
      int startingAddress = 0;
#if !FxCop
      SourceContext sourceContext = new SourceContext();
#if !CodeContracts
      sourceContext.StartPos = this.counter;
#endif
#endif
#if !ROTOR
      if (this.method.contextForOffset != null){
        object sctx = this.method.contextForOffset[this.counter+1];
        if (sctx != null) sourceContext = (SourceContext)sctx;
#if ILOFFSETS
        else
        {
          sourceContext = this.lastSourceContext;
        }
#endif
      }
#endif
      while (true){
        bool isStatement = false;
        startingAddress = this.counter+1; //Add one so that it is never zero (the latter means no entry to the TrivialHashtable)
#if FxCop || ILOFFSETS
        this.ilOffset = this.counter;
        this.opCode = this.GetOpCode();
#else
        OpCode opCode = this.GetOpCode();
#endif
#if FxCop
        if (this.handlerMap.TryGetValue(this.ilOffset, out expr)){
          expr.sourceContext = sourceContext;
          expr.ILOffset = this.ilOffset;
          this.operandStack.Push(expr);
        }
#endif
        switch (opCode){
          case OpCode.Nop: statement = new Statement(NodeType.Nop); goto done;
          case OpCode.Break: statement = new Statement(NodeType.DebugBreak); goto done;
          case OpCode.Ldarg_0: expr = this.Parameters(0); break;
          case OpCode.Ldarg_1: expr = this.Parameters(1); break;
          case OpCode.Ldarg_2: expr = this.Parameters(2); break;
          case OpCode.Ldarg_3: expr = this.Parameters(3); break;
          case OpCode.Ldloc_0: expr = this.locals[0]; break;
          case OpCode.Ldloc_1: expr = this.locals[1]; break;
          case OpCode.Ldloc_2: expr = this.locals[2]; break;
          case OpCode.Ldloc_3: expr = this.locals[3]; break;
          case OpCode.Stloc_0: statement = new AssignmentStatement(this.locals[0], PopOperand()); goto done;
          case OpCode.Stloc_1: statement = new AssignmentStatement(this.locals[1], PopOperand()); goto done;
          case OpCode.Stloc_2: statement = new AssignmentStatement(this.locals[2], PopOperand()); goto done;
          case OpCode.Stloc_3: statement = new AssignmentStatement(this.locals[3], PopOperand()); goto done;
          case OpCode.Ldarg_S: expr = this.Parameters(this.GetByte()); break;
          case OpCode.Ldarga_S: expr = SetType(new UnaryExpression(this.Parameters(this.GetByte()), NodeType.AddressOf)); break;
          case OpCode.Starg_S: statement = new AssignmentStatement(this.Parameters(this.GetByte()), PopOperand()); goto done;
          case OpCode.Ldloc_S: expr = this.locals[this.GetByte()]; break;
          case OpCode.Ldloca_S: expr = SetType(new UnaryExpression(this.locals[this.GetByte()], NodeType.AddressOf)); break;
          case OpCode.Stloc_S: statement = new AssignmentStatement(this.locals[this.GetByte()], PopOperand()); goto done;
#if true || CodeContracts
          case OpCode.Ldnull: expr = Literal.Null; break;
          case OpCode.Ldc_I4_M1: expr = Literal.Int32MinusOne; break;
          case OpCode.Ldc_I4_0: expr = Literal.Int32Zero; break;
          case OpCode.Ldc_I4_1: expr = Literal.Int32One; break;
          case OpCode.Ldc_I4_2: expr = Literal.Int32Two; break;
#else
          case OpCode.Ldnull: expr = new Literal(null, CoreSystemTypes.Object); break;
          case OpCode.Ldc_I4_M1: expr = new Literal(-1, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_0: expr = new Literal(0, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_1: expr = new Literal(1, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_2: expr = new Literal(2, CoreSystemTypes.Int32); break;
#endif
          case OpCode.Ldc_I4_3: expr = new Literal(3, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_4: expr = new Literal(4, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_5: expr = new Literal(5, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_6: expr = new Literal(6, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_7: expr = new Literal(7, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_8: expr = new Literal(8, CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4_S: expr = new Literal((int)this.GetSByte(), CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I4: expr = new Literal(this.GetInt32(), CoreSystemTypes.Int32); break;
          case OpCode.Ldc_I8: expr = new Literal(this.GetInt64(), CoreSystemTypes.Int64); break;
          case OpCode.Ldc_R4: expr = new Literal(this.GetSingle(), CoreSystemTypes.Single); break;
          case OpCode.Ldc_R8: expr = new Literal(this.GetDouble(), CoreSystemTypes.Double); break;
          case OpCode.Dup: statement = new ExpressionStatement(new Expression(NodeType.Dup)); goto done;
          case OpCode.Pop: statement = new ExpressionStatement(new UnaryExpression(PopOperand(), NodeType.Pop)); goto done;
          case OpCode.Jmp: expr = this.ParseCall(NodeType.Jmp, out isStatement); if (isStatement) goto done; break;
          case OpCode.Call: expr = this.ParseCall(NodeType.Call, out isStatement); if (isStatement) goto done; break;
          case OpCode.Calli: expr = this.ParseCalli(out isStatement); if (isStatement) goto done; break;
          case OpCode.Ret:
            Expression retVal = BodyParser.TypeIsVoid(this.method.ReturnType) ? null : PopOperand();
            statement = new Return(retVal); 
            transferStatement = true; goto done;
          case OpCode.Br_S: statement = this.ParseBranch(NodeType.Nop, 0, true, false); transferStatement = true; goto done;
          case OpCode.Brfalse_S: statement = this.ParseBranch(NodeType.LogicalNot, 1, true, false); transferStatement = true; goto done;
          case OpCode.Brtrue_S: statement = this.ParseBranch(NodeType.Nop, 1, true, false); transferStatement = true; goto done;
          case OpCode.Beq_S: statement = this.ParseBranch(NodeType.Eq, 2, true, false); transferStatement = true; goto done;
          case OpCode.Bge_S: statement = this.ParseBranch(NodeType.Ge, 2, true, false); transferStatement = true; goto done;
          case OpCode.Bgt_S: statement = this.ParseBranch(NodeType.Gt, 2, true, false); transferStatement = true; goto done;
          case OpCode.Ble_S: statement = this.ParseBranch(NodeType.Le, 2, true, false); transferStatement = true; goto done;
          case OpCode.Blt_S: statement = this.ParseBranch(NodeType.Lt, 2, true, false); transferStatement = true; goto done;
          case OpCode.Bne_Un_S: statement = this.ParseBranch(NodeType.Ne, 2, true, true); transferStatement = true; goto done;
          case OpCode.Bge_Un_S: statement = this.ParseBranch(NodeType.Ge, 2, true, true); transferStatement = true; goto done;
          case OpCode.Bgt_Un_S: statement = this.ParseBranch(NodeType.Gt, 2, true, true); transferStatement = true; goto done;
          case OpCode.Ble_Un_S: statement = this.ParseBranch(NodeType.Le, 2, true, true); transferStatement = true; goto done;
          case OpCode.Blt_Un_S: statement = this.ParseBranch(NodeType.Lt, 2, true, true); transferStatement = true; goto done;
          case OpCode.Br: statement = this.ParseBranch(NodeType.Nop, 0, false, false); transferStatement = true; goto done;
          case OpCode.Brfalse: statement = this.ParseBranch(NodeType.LogicalNot, 1, false, false); transferStatement = true; goto done;
          case OpCode.Brtrue: statement = this.ParseBranch(NodeType.Nop, 1, false, false); transferStatement = true; goto done;
          case OpCode.Beq: statement = this.ParseBranch(NodeType.Eq, 2, false, false); transferStatement = true; goto done;
          case OpCode.Bge: statement = this.ParseBranch(NodeType.Ge, 2, false, false); transferStatement = true; goto done;
          case OpCode.Bgt: statement = this.ParseBranch(NodeType.Gt, 2, false, false); transferStatement = true; goto done;
          case OpCode.Ble: statement = this.ParseBranch(NodeType.Le, 2, false, false); transferStatement = true; goto done;
          case OpCode.Blt: statement = this.ParseBranch(NodeType.Lt, 2, false, false); transferStatement = true; goto done;
          case OpCode.Bne_Un: statement = this.ParseBranch(NodeType.Ne, 2, false, true); transferStatement = true; goto done;
          case OpCode.Bge_Un: statement = this.ParseBranch(NodeType.Ge, 2, false, true); transferStatement = true; goto done;
          case OpCode.Bgt_Un: statement = this.ParseBranch(NodeType.Gt, 2, false, true); transferStatement = true; goto done;
          case OpCode.Ble_Un: statement = this.ParseBranch(NodeType.Le, 2, false, true); transferStatement = true; goto done;
          case OpCode.Blt_Un: statement = this.ParseBranch(NodeType.Lt, 2, false, true); transferStatement = true; goto done;
          case OpCode.Switch: statement = this.ParseSwitchInstruction(); transferStatement = true; goto done;
          case OpCode.Ldind_I1: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Int8, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_U1: expr = new AddressDereference(PopOperand(), CoreSystemTypes.UInt8, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_I2: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Int16, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_U2: expr = new AddressDereference(PopOperand(), CoreSystemTypes.UInt16, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_I4: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Int32, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_U4: expr = new AddressDereference(PopOperand(), CoreSystemTypes.UInt32, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_I8: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Int64, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_I: expr = new AddressDereference(PopOperand(), CoreSystemTypes.IntPtr, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_R4: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Single, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_R8: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Double, this.isVolatile, this.alignment); break;
          case OpCode.Ldind_Ref: expr = new AddressDereference(PopOperand(), CoreSystemTypes.Object, this.isVolatile, this.alignment); break;
          case OpCode.Stind_Ref: statement = this.ParseStoreIndirect(CoreSystemTypes.Object); goto done;
          case OpCode.Stind_I1: statement = this.ParseStoreIndirect(CoreSystemTypes.Int8); goto done;
          case OpCode.Stind_I2: statement = this.ParseStoreIndirect(CoreSystemTypes.Int16); goto done;
          case OpCode.Stind_I4: statement = this.ParseStoreIndirect(CoreSystemTypes.Int32); goto done;
          case OpCode.Stind_I8: statement = this.ParseStoreIndirect(CoreSystemTypes.Int64); goto done;
          case OpCode.Stind_R4: statement = this.ParseStoreIndirect(CoreSystemTypes.Single); goto done;
          case OpCode.Stind_R8: statement = this.ParseStoreIndirect(CoreSystemTypes.Double); goto done;
          case OpCode.Add: expr = this.ParseBinaryOperation(NodeType.Add); break;
          case OpCode.Sub: expr = this.ParseBinaryOperation(NodeType.Sub); break;
          case OpCode.Mul: expr = this.ParseBinaryOperation(NodeType.Mul); break;
          case OpCode.Div: expr = this.ParseBinaryOperation(NodeType.Div); break;
          case OpCode.Div_Un: expr = this.ParseBinaryOperation(NodeType.Div_Un); break;
          case OpCode.Rem: expr = this.ParseBinaryOperation(NodeType.Rem); break;
          case OpCode.Rem_Un: expr = this.ParseBinaryOperation(NodeType.Rem_Un); break;
          case OpCode.And: expr = this.ParseBinaryOperation(NodeType.And); break;
          case OpCode.Or: expr = this.ParseBinaryOperation(NodeType.Or); break;
          case OpCode.Xor: expr = this.ParseBinaryOperation(NodeType.Xor); break;
          case OpCode.Shl: expr = this.ParseBinaryOperation(NodeType.Shl); break;
          case OpCode.Shr: expr = this.ParseBinaryOperation(NodeType.Shr); break;
          case OpCode.Shr_Un: expr = this.ParseBinaryOperation(NodeType.Shr_Un); break;
          case OpCode.Neg: expr = this.ParseUnaryOperation(NodeType.Neg); break;
          case OpCode.Not: expr = this.ParseUnaryOperation(NodeType.Not); break;
          case OpCode.Conv_I1: expr = new UnaryExpression(PopOperand(), NodeType.Conv_I1, CoreSystemTypes.Int8); break;
          case OpCode.Conv_I2: expr = new UnaryExpression(PopOperand(), NodeType.Conv_I2, CoreSystemTypes.Int16); break;
          case OpCode.Conv_I4: expr = new UnaryExpression(PopOperand(), NodeType.Conv_I4, CoreSystemTypes.Int32); break;
          case OpCode.Conv_I8: expr = new UnaryExpression(PopOperand(), NodeType.Conv_I8, CoreSystemTypes.Int64); break;
          case OpCode.Conv_R4: expr = new UnaryExpression(PopOperand(), NodeType.Conv_R4, CoreSystemTypes.Single); break;
          case OpCode.Conv_R8: expr = new UnaryExpression(PopOperand(), NodeType.Conv_R8, CoreSystemTypes.Double); break;
          case OpCode.Conv_U4: expr = new UnaryExpression(PopOperand(), NodeType.Conv_U4, CoreSystemTypes.UInt32); break;
          case OpCode.Conv_U8: expr = new UnaryExpression(PopOperand(), NodeType.Conv_U8, CoreSystemTypes.UInt64); break;
          case OpCode.Callvirt: expr = this.ParseCall(NodeType.Callvirt, out isStatement); if (isStatement) goto done; break;
          case OpCode.Cpobj: statement = this.ParseCopyObject(); goto done;
          case OpCode.Ldobj: expr = new AddressDereference(PopOperand(), (TypeNode)this.GetMemberFromToken(), this.isVolatile, this.alignment); break;
          case OpCode.Ldstr: expr = new Literal(this.GetStringFromToken(), CoreSystemTypes.String); break;
          case OpCode.Newobj: expr = this.ParseConstruct(); break;
          case OpCode.Castclass: expr = ParseTypeCheck(PopOperand(), (TypeNode)this.GetMemberFromToken(), NodeType.Castclass); break;
          case OpCode.Isinst: expr = ParseTypeCheck(PopOperand(), (TypeNode)this.GetMemberFromToken(), NodeType.Isinst); break;
          case OpCode.Conv_R_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_R_Un, CoreSystemTypes.Double); break;
          case OpCode.Unbox: expr = ParseTypeCheck(PopOperand(), (TypeNode)this.GetMemberFromToken(), NodeType.Unbox); break;
          case OpCode.Throw: statement = new Throw(PopOperand()); transferStatement = true; goto done;
          case OpCode.Ldfld: 
            expr = new MemberBinding(PopOperand(), this.GetMemberFromToken(), this.isVolatile, this.alignment);
            break;
          case OpCode.Ldflda: 
            expr = SetType(new UnaryExpression(new MemberBinding(PopOperand(), this.GetMemberFromToken(), this.isVolatile, this.alignment), NodeType.AddressOf)); 
            break;
          case OpCode.Stfld: statement = this.ParseStoreField(); goto done;
          case OpCode.Ldsfld: expr = new MemberBinding(null, this.GetMemberFromToken(new FieldInfo { IsStatic = true }), this.isVolatile, this.alignment); break;
          case OpCode.Ldsflda: expr = SetType(new UnaryExpression(new MemberBinding(null, this.GetMemberFromToken(new FieldInfo { IsStatic = true }), this.isVolatile, this.alignment), NodeType.AddressOf)); break;
          case OpCode.Stsfld: statement = new AssignmentStatement(new MemberBinding(null, this.GetMemberFromToken(), this.isVolatile, this.alignment), PopOperand()); goto done;
          case OpCode.Stobj: statement = this.ParseStoreIndirect((TypeNode)this.GetMemberFromToken()); goto done;
          case OpCode.Conv_Ovf_I1_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I1_Un, CoreSystemTypes.Int8); break;
          case OpCode.Conv_Ovf_I2_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I2_Un, CoreSystemTypes.Int16); break;
          case OpCode.Conv_Ovf_I4_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I4_Un, CoreSystemTypes.Int32); break;
          case OpCode.Conv_Ovf_I8_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I8_Un, CoreSystemTypes.Int64); break;
          case OpCode.Conv_Ovf_U1_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U1_Un, CoreSystemTypes.UInt8); break;
          case OpCode.Conv_Ovf_U2_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U2_Un, CoreSystemTypes.UInt16); break;
          case OpCode.Conv_Ovf_U4_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U4_Un, CoreSystemTypes.UInt32); break;
          case OpCode.Conv_Ovf_U8_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U8_Un, CoreSystemTypes.UInt64); break;
          case OpCode.Conv_Ovf_I_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I_Un, CoreSystemTypes.IntPtr); break;
          case OpCode.Conv_Ovf_U_Un: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U_Un, CoreSystemTypes.UIntPtr); break;
          case OpCode.Box: 
            TypeNode t = (TypeNode)this.GetMemberFromToken();
            TypeNode bt = t is EnumNode ? CoreSystemTypes.Enum : CoreSystemTypes.ValueType;
            expr = new BinaryExpression(PopOperand(), new Literal(t, CoreSystemTypes.Type), NodeType.Box, bt); break;
          case OpCode.Newarr: expr = this.ParseNewArray(); break;
          case OpCode.Ldlen: expr = new UnaryExpression(PopOperand(), NodeType.Ldlen, CoreSystemTypes.UIntPtr); break;
          case OpCode.Ldelema: expr = this.ParseArrayElementLoadAddress(); break;
          case OpCode.Ldelem_I1: 
          case OpCode.Ldelem_U1: 
          case OpCode.Ldelem_I2: 
          case OpCode.Ldelem_U2: 
          case OpCode.Ldelem_I4: 
          case OpCode.Ldelem_U4: 
          case OpCode.Ldelem_I8: 
          case OpCode.Ldelem_I: 
          case OpCode.Ldelem_R4: 
          case OpCode.Ldelem_R8: 
          case OpCode.Ldelem_Ref: expr = this.ParseArrayElementLoad(opCode, null); break;
          case OpCode.Stelem_I:
          case OpCode.Stelem_I1:
          case OpCode.Stelem_I2:
          case OpCode.Stelem_I4:
          case OpCode.Stelem_I8:
          case OpCode.Stelem_R4:
          case OpCode.Stelem_R8:
          case OpCode.Stelem_Ref: statement = this.ParseArrayElementAssignment(opCode); goto done;
          case OpCode.Ldelem: expr = this.ParseArrayElementLoad(opCode, null); break;
          case OpCode.Stelem: statement = this.ParseArrayElementAssignment(opCode); goto done;
          case OpCode.Unbox_Any: expr = ParseTypeCheck(PopOperand(), (TypeNode)this.GetMemberFromToken(), NodeType.UnboxAny); break;
          case OpCode.Conv_Ovf_I1: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I1, CoreSystemTypes.Int8); break;
          case OpCode.Conv_Ovf_U1: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U1, CoreSystemTypes.UInt8); break;
          case OpCode.Conv_Ovf_I2: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I2, CoreSystemTypes.Int16); break;
          case OpCode.Conv_Ovf_U2: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U2, CoreSystemTypes.UInt16); break;
          case OpCode.Conv_Ovf_I4: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I4, CoreSystemTypes.Int32); break;
          case OpCode.Conv_Ovf_U4: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U4, CoreSystemTypes.UInt32); break;
          case OpCode.Conv_Ovf_I8: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I8, CoreSystemTypes.Int64); break;
          case OpCode.Conv_Ovf_U8: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U8, CoreSystemTypes.UInt64); break;
          case OpCode.Refanyval: expr = new BinaryExpression(PopOperand(), new Literal(this.GetMemberFromToken(), CoreSystemTypes.Type), NodeType.Refanyval, CoreSystemTypes.IntPtr); break;
          case OpCode.Ckfinite: expr = this.ParseUnaryOperation(NodeType.Ckfinite); break;
          case OpCode.Mkrefany: expr = new BinaryExpression(PopOperand(), new Literal(this.GetMemberFromToken(), CoreSystemTypes.Type), NodeType.Mkrefany, CoreSystemTypes.DynamicallyTypedReference); break;
          case OpCode.Ldtoken: expr = ParseLoadRuntimeMetadataToken(); break;
          case OpCode.Conv_U2: expr = new UnaryExpression(PopOperand(), NodeType.Conv_U2, CoreSystemTypes.UInt16); break;
          case OpCode.Conv_U1: expr = new UnaryExpression(PopOperand(), NodeType.Conv_U1, CoreSystemTypes.UInt8); break;
          case OpCode.Conv_I: expr = new UnaryExpression(PopOperand(), NodeType.Conv_I, CoreSystemTypes.IntPtr); break;
          case OpCode.Conv_Ovf_I: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_I, CoreSystemTypes.IntPtr); break;
          case OpCode.Conv_Ovf_U: expr = new UnaryExpression(PopOperand(), NodeType.Conv_Ovf_U, CoreSystemTypes.UIntPtr); break;
          case OpCode.Add_Ovf: expr = this.ParseBinaryOperation(NodeType.Add_Ovf); break;
          case OpCode.Add_Ovf_Un: expr = this.ParseBinaryOperation(NodeType.Add_Ovf_Un); break;
          case OpCode.Mul_Ovf: expr = this.ParseBinaryOperation(NodeType.Mul_Ovf); break;
          case OpCode.Mul_Ovf_Un: expr = this.ParseBinaryOperation(NodeType.Mul_Ovf_Un); break;
          case OpCode.Sub_Ovf: expr = this.ParseBinaryOperation(NodeType.Sub_Ovf); break;
          case OpCode.Sub_Ovf_Un: expr = this.ParseBinaryOperation(NodeType.Sub_Ovf_Un); break;
          case OpCode.Endfinally: statement = new EndFinally(); transferStatement = true; goto done;
          case OpCode.Leave: statement = this.ParseBranch(NodeType.Nop, 0, false, false, true); transferStatement = true; goto done;
          case OpCode.Leave_S: statement = this.ParseBranch(NodeType.Nop, 0, true, false, true); transferStatement = true; goto done;
          case OpCode.Stind_I: statement = this.ParseStoreIndirect(CoreSystemTypes.IntPtr); goto done;
          case OpCode.Conv_U: expr = new UnaryExpression(PopOperand(), NodeType.Conv_U, CoreSystemTypes.UIntPtr); break;
          case OpCode.Arglist: expr = new Expression(NodeType.Arglist, CoreSystemTypes.ArgIterator); break;
          case OpCode.Ceq: expr = this.ParseBinaryComparison(NodeType.Ceq); break;
          case OpCode.Cgt: expr = this.ParseBinaryComparison(NodeType.Cgt); break;
          case OpCode.Cgt_Un: expr = this.ParseBinaryComparison(NodeType.Cgt_Un); break;
          case OpCode.Clt: expr = this.ParseBinaryComparison(NodeType.Clt); break;
          case OpCode.Clt_Un: expr = this.ParseBinaryComparison(NodeType.Clt_Un); break;
          case OpCode.Ldftn: expr = new UnaryExpression(new MemberBinding(null, this.GetMemberFromToken()), NodeType.Ldftn, CoreSystemTypes.IntPtr); break;
          case OpCode.Ldvirtftn: expr = new BinaryExpression(PopOperand(), new MemberBinding(null, this.GetMemberFromToken()), NodeType.Ldvirtftn, CoreSystemTypes.IntPtr); break;
          case OpCode.Ldarg: expr = this.Parameters((ushort)this.GetInt16()); break;
          case OpCode.Ldarga: expr = SetType(new UnaryExpression(this.Parameters((ushort)this.GetInt16()), NodeType.AddressOf)); break;
          case OpCode.Starg: statement = new AssignmentStatement(this.Parameters((ushort)this.GetInt16()), PopOperand()); goto done;
          case OpCode.Ldloc: expr = this.locals[(ushort)this.GetInt16()]; break;
          case OpCode.Ldloca: expr = SetType(new UnaryExpression(this.locals[(ushort)this.GetInt16()], NodeType.AddressOf)); break;
          case OpCode.Stloc: statement = new AssignmentStatement(this.locals[(ushort)this.GetInt16()], PopOperand()); goto done;
          case OpCode.Localloc: expr = new UnaryExpression(PopOperand(), NodeType.Localloc, CoreSystemTypes.Void); break;
          case OpCode.Endfilter: statement = new EndFilter(PopOperand()); transferStatement = true; goto done;
          case OpCode.Unaligned_: this.alignment = this.GetByte(); continue;
          case OpCode.Volatile_: this.isVolatile = true; continue;
          case OpCode.Tail_: this.isTailCall = true; continue;
          case OpCode.Initobj: statement = this.ParseInitObject(); goto done;
          case OpCode.Constrained_: this.constraint = this.GetMemberFromToken() as TypeNode; continue;
          case OpCode.Cpblk: expr = this.ParseTernaryOperation(NodeType.Cpblk); goto done;
          case OpCode.Initblk: expr = this.ParseTernaryOperation(NodeType.Initblk); goto done;
          case OpCode.Rethrow: statement = new Throw(null); statement.NodeType = NodeType.Rethrow; transferStatement = true; goto done;
          case OpCode.Sizeof: expr = new UnaryExpression(new Literal(this.GetMemberFromToken(), CoreSystemTypes.Type), NodeType.Sizeof, CoreSystemTypes.Int32); break;
          case OpCode.Refanytype: expr = new UnaryExpression(PopOperand(), NodeType.Refanytype, CoreSystemTypes.RuntimeTypeHandle); break;
          case OpCode.Readonly_: this.isReadOnly = true; continue;
          default: throw new InvalidMetadataException(ExceptionStrings.UnknownOpCode);
        }
        if (this.blockMap[this.counter+1] != null){
          transferStatement = true; //Falls through to the next basic block, so implicitly a "transfer" statement
          goto done;
        }
        //^ assume expr != null;
#if FxCop
        expr.sourceContext = sourceContext;
#endif
#if FxCop || ILOFFSETS
        expr.ILOffset = this.ilOffset;
#endif
        this.operandStack.Push(expr);
        this.isReadOnly = false;
        this.isVolatile = false;
        this.isTailCall = false;        
        this.alignment = -1;
      }
    done:
      for (int i = 0; i <= this.operandStack.top; i++){
        Expression e = this.operandStack.elements[i];
        //^ assume e != null;
        Statement s = new ExpressionStatement(e);
#if FxCop
        s.SourceContext = this.sourceContext;
        s.ILOffset = this.ilOffset;
#endif
#if ILOFFSETS
        s.ILOffset = this.ilOffset;
        s.SourceContext = sourceContext;
#endif
        statementList.Add(s);
      }
      this.operandStack.top = -1;
      if (statement == null) {
        statement = new ExpressionStatement(expr);
#if FxCop
        expr.sourceContext = this.sourceContext;
#endif
#if FxCop || ILOFFSETS
        expr.ILOffset = this.ilOffset;
#endif
      }
      statement.SourceContext = sourceContext;
#if FxCop || ILOFFSETS
      statement.ILOffset = this.ilOffset;
#endif
#if ILOFFSETS
      this.lastSourceContext = sourceContext;
#endif
      statementList.Add(statement);
      if (transferStatement) return true;
      return this.blockMap[this.counter+1] != null;
    }
    private AssignmentStatement ParseStoreField(){
      Expression rhvalue = PopOperand();
      Expression thisob = PopOperand();
      AssignmentStatement s = new AssignmentStatement(new MemberBinding(thisob, this.GetMemberFromToken(), this.isVolatile, this.alignment), rhvalue);
      return s;
    }
    private AssignmentStatement ParseStoreIndirect(TypeNode type){
      Expression rhvalue = PopOperand();
      Expression lhaddr = PopOperand();
      return new AssignmentStatement(new AddressDereference(lhaddr, type, this.isVolatile, this.alignment), rhvalue);
    }
    private SwitchInstruction ParseSwitchInstruction(){
      int numTargets = this.GetInt32();
      int offset = this.counter + numTargets*4;
      BlockList targetList = new BlockList(numTargets);
      for (int i = 0; i < numTargets; i++){
        int targetAddress = this.GetInt32() + offset;
        targetList.Add(Reader.GetOrCreateBlock(this.blockMap, targetAddress));
      }
      return new SwitchInstruction(PopOperand(), targetList);
    }
    private TernaryExpression ParseTernaryOperation(NodeType oper){
      Expression op3 = PopOperand();
      Expression op2 = PopOperand();
      Expression op1 = PopOperand();
      return new TernaryExpression(op1, op2, op3, oper, null);
    }
    private void CreateBlocksForBranchTargets(){
      int savedPosition = bodyReader.Position;
      while (this.counter < this.size)
        this.ProcessOneILInstruction();
      this.counter = 0;
      bodyReader.Position = savedPosition;
    }
    private void ProcessOneILInstruction(){
      OpCode opc = this.GetOpCode();
      switch(opc){
        case OpCode.Ldarg_S:
        case OpCode.Ldarga_S:
        case OpCode.Starg_S:
        case OpCode.Ldloc_S:
        case OpCode.Ldloca_S:
        case OpCode.Stloc_S:
        case OpCode.Ldc_I4_S:
          this.GetByte(); return;
        case OpCode.Ldc_I4:
        case OpCode.Jmp:
        case OpCode.Call:
        case OpCode.Calli:
        case OpCode.Callvirt:
        case OpCode.Cpobj:
        case OpCode.Ldobj:
        case OpCode.Ldstr:
        case OpCode.Newobj:
        case OpCode.Castclass:
        case OpCode.Isinst:
        case OpCode.Unbox:
        case OpCode.Ldfld:
        case OpCode.Ldflda:
        case OpCode.Stfld:
        case OpCode.Ldsfld:
        case OpCode.Ldsflda:
        case OpCode.Stsfld:
        case OpCode.Stobj:
        case OpCode.Box:
        case OpCode.Newarr:
        case OpCode.Ldelema:
        case OpCode.Ldelem:
        case OpCode.Stelem:
        case OpCode.Unbox_Any:
        case OpCode.Refanyval:
        case OpCode.Mkrefany: 
        case OpCode.Ldtoken:
          this.GetInt32(); return;
        case OpCode.Ldc_I8:
          this.GetInt64(); return;
        case OpCode.Ldc_R4: 
          this.GetSingle(); return;
        case OpCode.Ldc_R8:
          this.GetDouble(); return;
        case OpCode.Br_S: 
        case OpCode.Brfalse_S: 
        case OpCode.Brtrue_S: 
        case OpCode.Beq_S: 
        case OpCode.Bge_S: 
        case OpCode.Bgt_S: 
        case OpCode.Ble_S: 
        case OpCode.Blt_S: 
        case OpCode.Bne_Un_S: 
        case OpCode.Bge_Un_S: 
        case OpCode.Bgt_Un_S: 
        case OpCode.Ble_Un_S: 
        case OpCode.Blt_Un_S: 
        case OpCode.Leave_S:
          this.SkipBranch(true); return;
        case OpCode.Br: 
        case OpCode.Brfalse: 
        case OpCode.Brtrue: 
        case OpCode.Beq: 
        case OpCode.Bge: 
        case OpCode.Bgt: 
        case OpCode.Ble: 
        case OpCode.Blt: 
        case OpCode.Bne_Un: 
        case OpCode.Bge_Un: 
        case OpCode.Bgt_Un: 
        case OpCode.Ble_Un: 
        case OpCode.Blt_Un: 
        case OpCode.Leave:
          this.SkipBranch(false); return;
        case OpCode.Switch:
          this.SkipSwitch(); return;
        case OpCode.Ldftn:
        case OpCode.Ldvirtftn:
        case OpCode.Initobj:
        case OpCode.Constrained_:
        case OpCode.Sizeof:
          this.GetInt32(); return;
        case OpCode.Ldarg:
        case OpCode.Ldarga:
        case OpCode.Ldloc:
        case OpCode.Ldloca:
        case OpCode.Starg:
        case OpCode.Stloc:
          this.GetInt16(); return;
        case OpCode.Unaligned_:
          this.GetByte(); return;
        default:
          return;
      }
    }
    private void SkipBranch(bool shortOffset){
      int offset = shortOffset ? this.GetSByte() : this.GetInt32();
      Reader.GetOrCreateBlock(blockMap, this.counter + offset);
    }
    private void SkipSwitch(){
      int numCases = this.GetInt32();
      int offset = this.counter + numCases*4;
      for (int i = 0; i < numCases; i++){
        int targetAddress = this.GetInt32() + offset;
        Reader.GetOrCreateBlock(this.blockMap, targetAddress);
      }    
    }
    private Expression PopOperand()
    {
        return this.operandStack.Pop();
    }
#if FxCop || ILOFFSETS
    private OpCode opCode;
    private int ilOffset;
#endif
#if ILOFFSETS
    SourceContext lastSourceContext;
#endif
#if FxCop
    private SourceContext sourceContext;
    private Block currentBlock;
    private Dictionary<Block, List<TryNode>> tryMap;
    private Dictionary<int, Expression> handlerMap;
    internal StatementList/*!*/ ParseStatements() {
      this.tryMap = new Dictionary<Block, List<TryNode>>();
      this.handlerMap = new Dictionary<int, Expression>();
      this.ParseHeader();
      this.CreateBlocksForBranchTargets();
      currentBlock = null;
      this.sourceContext = new SourceContext();
      while (this.counter < size) {
        if (currentBlock == null) {
          currentBlock = Reader.GetOrCreateBlock(this.blockMap, this.counter);
        }
        bool endOfBasicBlock = this.ParseStatement(currentBlock);
        if (endOfBasicBlock) {
          currentBlock.SourceContext = currentBlock.Statements[0].SourceContext;
          currentBlock = null;
        }
      }
      Reader.GetOrCreateBlock(this.blockMap, this.counter);
      int counter = 0;
      Block block = new Block();
      block.Statements = new StatementList();
      ProcessBlock(block, ref counter, this.size, null);
      return block.Statements;
    }
    override protected void ParseExceptionHandlerEntry(bool smallSection) {
      int dataSize = this.reader.tables.GetByte();
      int n = (int)(ushort)this.reader.tables.GetInt16();
      if (smallSection)
        n = dataSize / 12;
      else
        n = (dataSize + (n << 8)) / 24;
      for (int i = 0; i < n; i++) {
        int flags, tryOffset, tryLength, handlerOffset, handlerLength, tokenOrOffset;
        if (smallSection) {
          flags = this.reader.tables.GetInt16();
          tryOffset = this.reader.tables.GetUInt16();
          tryLength = this.reader.tables.GetByte();
          handlerOffset = this.reader.tables.GetUInt16();
          handlerLength = this.reader.tables.GetByte();
        }
        else {
          flags = this.reader.tables.GetInt32();
          tryOffset = this.reader.tables.GetInt32();
          tryLength = this.reader.tables.GetInt32();
          handlerOffset = this.reader.tables.GetInt32();
          handlerLength = this.reader.tables.GetInt32();
        }
        tokenOrOffset = this.reader.tables.GetInt32();
        Block tryStartBlock = Reader.GetOrCreateBlock(this.blockMap, tryOffset);
        Block blockAfterTryEnd = Reader.GetOrCreateBlock(this.blockMap, tryOffset + tryLength);
        Block handlerStartBlock = Reader.GetOrCreateBlock(this.blockMap, handlerOffset);
        Block blockAfterHandlerEnd = Reader.GetOrCreateBlock(this.blockMap, handlerOffset + handlerLength);
        List<TryNode> tryList = null;
        if (!this.tryMap.TryGetValue(tryStartBlock, out tryList)) {
          this.tryMap[tryStartBlock] = tryList = new List<TryNode>();
        }
        TryNode currentTry = null;
        int tryEnd = tryOffset + tryLength;
        foreach (TryNode t in tryList) {
          if (t.tryEnd == tryEnd) {
            currentTry = t;
            break;
          }
        }
        if (currentTry == null) {
          currentTry = new TryNode();
          currentTry.tryEnd = tryEnd;
          tryList.Add(currentTry);
        }
        int handlerEnd = handlerOffset + handlerLength;
        if (currentTry.handlersEnd < handlerEnd)
          currentTry.handlersEnd = handlerEnd;

        Debug.Assert((int)flags != 3);
        Debug.Assert((int)flags < 5);

        switch (flags) {
          case 0x00:
            // for a catch handler, tokenOrOffset represents
            // the metadata token of the handler type. handlerOffset
            // is the literal offset for the catch block
            int pos = this.reader.tables.GetCurrentPosition();
            TypeNode filterType = (TypeNode)this.reader.GetMemberFromToken(tokenOrOffset);
            this.reader.tables.SetCurrentPosition(pos);
            string variableName = "$exception" + this.handlerMap.Count.ToString(CultureInfo.InvariantCulture);
            StackVariable exception = new StackVariable(filterType, variableName);
            CatchNode c = new CatchNode(handlerStartBlock, exception, filterType);
            c.handlerEnd = handlerEnd;
            currentTry.Catchers.Add(c);
            this.handlerMap[handlerOffset] = exception;
            break;
          case 0x01:
            // for a filter, tokenOrOffset represents the IL offset
            // of the filter block. handlerOffset represents
            // the IL offset of the associated catch handler
            Block filterExpression = Reader.GetOrCreateBlock(blockMap, tokenOrOffset);
            variableName = "$exception" + this.handlerMap.Count.ToString(CultureInfo.InvariantCulture);
            exception = new StackVariable(CoreSystemTypes.Object, variableName);
            Filter filter = new Filter(filterExpression, exception);
            filter.handlerEnd = handlerOffset;
            c = new CatchNode(handlerStartBlock, exception, null, filter);
            c.handlerEnd = handlerEnd;
            currentTry.Catchers.Add(c);
            // note that handlerOffset would not be correct here!
            this.handlerMap[tokenOrOffset] = exception;
            break;
          case 0x02:
            FinallyNode f = new FinallyNode(handlerStartBlock);
            f.handlerEnd = handlerEnd;
            currentTry.Finally = f;
            break;
          case 0x04:
            FaultHandler fh = new FaultHandler(handlerStartBlock);
            fh.handlerEnd = handlerEnd;
            currentTry.FaultHandler = fh;
            break;
        }
      }
    }
    private void ProcessBlock(Block currentBlock, ref int counter, int blockEnd, Node blockNode) {
      while (true) {
        int lastCounter = counter;
        Block block = GetNextBlock(ref counter);
        if (block == null || block.ILOffset >= blockEnd) {
          counter = lastCounter;
          if (blockNode != null)
            blockNode.SourceContext = currentBlock.Statements[0].SourceContext;
          return;
        }
        if (this.tryMap.ContainsKey(block)) {
          ProcessTryBlock(currentBlock, block, ref counter);
        }
        else {
          if (currentBlock.Statements.Count == 0)
            currentBlock.SourceContext = block.SourceContext;
          currentBlock.Statements.Add(block);
        }
      }
    }
    private void ProcessTryBlock(Block outerBlock, Block currentBlock, ref int counter) {
      List<TryNode> tryList = this.tryMap[currentBlock];
      TryNode outerTry = tryList[tryList.Count - 1];
      outerBlock.Statements.Add(outerTry);
      tryList.Remove(outerTry);
      if (tryList.Count > 0) {
        outerTry.Block = new Block();
        outerTry.Block.Statements = new StatementList();
        ProcessTryBlock(outerTry.Block, currentBlock, ref counter);
      }
      else {
        outerTry.Block = currentBlock;
      }
      this.tryMap.Remove(currentBlock);
      ProcessBlock(outerTry.Block, ref counter, outerTry.tryEnd, outerTry);
      while (true) {
        int lastCounter = counter;
        Block block = GetNextBlock(ref counter);
        if (counter >= outerTry.handlersEnd) {
          counter = lastCounter;
          return;
        }
        int handlerEnd;
        Node handlerNode;
        GetHandlerEnd(outerTry, block, out handlerEnd, out handlerNode);
        ProcessBlock(block, ref counter, handlerEnd, handlerNode);
      }
    }
    private Block GetNextBlock(ref int counter) {
      while (true) {
        Block result = this.blockMap[counter + 1] as Block;
        ++counter;
        if (result != null || counter >= this.size)
          return result;
      }
    }
    private void GetHandlerEnd(TryNode t, Block block, out int handlerEnd, out Node handlerNode) {
      handlerEnd = Int32.MaxValue;
      handlerNode = null;
      int startPos = block.ILOffset;
      if (t.Finally != null
        && t.Finally.handlerEnd > startPos
        && t.Finally.handlerEnd < handlerEnd) {
        handlerEnd = t.Finally.handlerEnd;
        handlerNode = t.Finally;
      }
      foreach (CatchNode c in t.Catchers) {
        if (c.handlerEnd > startPos && c.handlerEnd < handlerEnd) {
          handlerEnd = c.handlerEnd;
          handlerNode = c;
        }
        if (c.Filter != null && c.Filter.handlerEnd > startPos && c.Filter.handlerEnd < handlerEnd) {
          handlerEnd = c.Filter.handlerEnd;
          handlerNode = c.Filter;
        }
      }
      if (t.FaultHandler != null
        && t.FaultHandler.handlerEnd > startPos
        && t.FaultHandler.handlerEnd < handlerEnd) {
        handlerEnd = t.FaultHandler.handlerEnd;
        handlerNode = t.FaultHandler;
      }
    }
#endif
  }
  internal class InstructionParser : ILParser{
    private readonly TrivialHashtable/*!*/ ehMap;
    internal InstructionParser(Reader/*!*/ reader, Method/*!*/ method, int methodIndex, int RVA)
      : base (reader, method, methodIndex, RVA){
      this.ehMap = new TrivialHashtable();
    }
    override protected void ParseExceptionHandlerEntry(bool smallSection){
      TrivialHashtable tryMap = new TrivialHashtable();
      int dataSize = this.reader.tables.GetByte();
      int n = (int)(ushort)this.reader.tables.GetInt16();
      if (smallSection)
        n = dataSize / 12;
      else
        n = (dataSize + (n << 8)) / 24;      
      for (int i = 0; i < n; i++){
        Instruction matchingInstruction;
        int flags, tryOffset, tryLength, handlerOffset, handlerLength, tokenOrOffset;
        if (smallSection){
          flags = this.reader.tables.GetInt16();
          tryOffset = this.reader.tables.GetUInt16();
          tryLength = this.reader.tables.GetByte();
          handlerOffset = this.reader.tables.GetUInt16();
          handlerLength = this.reader.tables.GetByte();
        }else{
          flags = this.reader.tables.GetInt32();
          tryOffset = this.reader.tables.GetInt32();
          tryLength = this.reader.tables.GetInt32();
          handlerOffset = this.reader.tables.GetInt32();
          handlerLength = this.reader.tables.GetInt32();
        }
        tokenOrOffset = this.reader.tables.GetInt32();
        if (tryMap[tryOffset+tryLength] == null){
          matchingInstruction = this.AddInstruction(OpCode._Try, tryOffset);
          this.AddInstruction(OpCode._EndTry, tryOffset+tryLength, matchingInstruction);
          tryMap[tryOffset+tryLength] = String.Empty;
        }
        switch(flags){
          case 0x00: 
            int pos = this.reader.tables.GetCurrentPosition();
            TypeNode catchType = (TypeNode)this.reader.GetMemberFromToken(tokenOrOffset);
            this.reader.tables.SetCurrentPosition(pos);
            matchingInstruction = this.AddInstruction(OpCode._Catch, handlerOffset, catchType);
            this.AddInstruction(OpCode._EndHandler, handlerOffset+handlerLength, matchingInstruction);
            break;
          case 0x01:
            matchingInstruction = this.AddInstruction(OpCode._Filter, tokenOrOffset);
            this.AddInstruction(OpCode._EndFilter, handlerOffset, matchingInstruction);
            matchingInstruction = this.AddInstruction(OpCode._Catch, handlerOffset);
            this.AddInstruction(OpCode._EndHandler, handlerOffset+handlerLength, matchingInstruction);
            break;
          case 0x02:
            matchingInstruction = this.AddInstruction(OpCode._Finally, handlerOffset);
            this.AddInstruction(OpCode._EndHandler, handlerOffset+handlerLength, matchingInstruction);
            break;
          case 0x04:
            matchingInstruction = this.AddInstruction(OpCode._Fault, handlerOffset);
            this.AddInstruction(OpCode._EndHandler, handlerOffset+handlerLength, matchingInstruction);
            break;
          default: throw new InvalidMetadataException(ExceptionStrings.BadExceptionHandlerType);
        }
      }
    }
    private Instruction AddInstruction(OpCode opCode, int offset){
      return this.AddInstruction(opCode, offset, null);
    }
    private Instruction AddInstruction(OpCode opCode, int offset, object value){
      Instruction instruction = new Instruction(opCode, offset, value);
      InstructionList instructions = (InstructionList)this.ehMap[offset+1];
      if (instructions == null) this.ehMap[offset+1] = instructions = new InstructionList(2);
      instructions.Add(instruction);
#if !ROTOR
      if (this.method.contextForOffset != null){
        object sctx = this.method.contextForOffset[offset + 1];
        if (sctx != null) instruction.SourceContext = (SourceContext)sctx;
      }
#endif
      return instruction;
    }
    private Int32List ParseSwitchInstruction(){
      int numTargets = this.GetInt32();
      Int32List result = new Int32List(numTargets);
      int offset = this.counter + numTargets*4;
      for (int i = 0; i < numTargets; i++){
        int targetAddress = this.GetInt32() + offset;
        result.Add(targetAddress);
      }
      return result;
    }
    internal InstructionList ParseInstructions(){
      this.ParseHeader();
      if (this.size == 0) return new InstructionList(0);
      InstructionList result = new InstructionList();
      result.Add(new Instruction(OpCode._Locals, 0, this.locals));
      while (this.counter <= size){
        InstructionList instructions = (InstructionList)this.ehMap[this.counter+1];
        if (instructions != null){
          for (int i = 0; i < instructions.Count; i++)
            result.Add(instructions[i]);
        }
        if (this.counter < size)
          result.Add(this.ParseInstruction());
        else 
          break;
      }
      return result;    
    }
    private SourceContext sourceContext = new SourceContext();
    internal Instruction ParseInstruction(){
      if (this.counter >= this.size) 
        return null;
      int offset = this.counter;
#if !ROTOR
      if (this.method.contextForOffset != null){
        object sctx = this.method.contextForOffset[offset+1];
        if (sctx != null) this.sourceContext = (SourceContext)sctx;
      }
#endif
      object value = null;
      OpCode opCode = this.GetOpCode();    
      switch(opCode){
        case OpCode.Nop:
        case OpCode.Break: 
          break;
        case OpCode.Ldarg_0: value = this.Parameters(0); break;
        case OpCode.Ldarg_1: value = this.Parameters(1); break;
        case OpCode.Ldarg_2: value = this.Parameters(2); break; 
        case OpCode.Ldarg_3: value = this.Parameters(3); break;
        case OpCode.Ldloc_0: value = this.locals[0]; break;
        case OpCode.Ldloc_1: value = this.locals[1]; break;
        case OpCode.Ldloc_2: value = this.locals[2]; break;
        case OpCode.Ldloc_3: value = this.locals[3]; break;
        case OpCode.Stloc_0: value = this.locals[0]; break;
        case OpCode.Stloc_1: value = this.locals[1]; break;
        case OpCode.Stloc_2: value = this.locals[2]; break;
        case OpCode.Stloc_3: value = this.locals[3]; break;
        case OpCode.Ldarg_S:  
        case OpCode.Ldarga_S:
        case OpCode.Starg_S:
          value = this.Parameters(this.GetByte()); break;
        case OpCode.Ldloc_S:
        case OpCode.Ldloca_S:
        case OpCode.Stloc_S:
          value = this.locals[this.GetByte()]; break;
        case OpCode.Ldnull: 
          break;
        case OpCode.Ldc_I4_M1: value = (Int32)(-1); break;
        case OpCode.Ldc_I4_0: value = (Int32)0; break;
        case OpCode.Ldc_I4_1: value = (Int32)1; break;
        case OpCode.Ldc_I4_2: value = (Int32)2; break;
        case OpCode.Ldc_I4_3: value = (Int32)3; break;
        case OpCode.Ldc_I4_4: value = (Int32)4; break;
        case OpCode.Ldc_I4_5: value = (Int32)5; break;
        case OpCode.Ldc_I4_6: value = (Int32)6; break;
        case OpCode.Ldc_I4_7: value = (Int32)7; break;
        case OpCode.Ldc_I4_8: value = (Int32)8; break;
        case OpCode.Ldc_I4_S: value = (Int32)this.GetSByte(); break;
        case OpCode.Ldc_I4: value = this.GetInt32(); break;
        case OpCode.Ldc_I8: value = this.GetInt64(); break;
        case OpCode.Ldc_R4: value = this.GetSingle(); break;
        case OpCode.Ldc_R8: value = this.GetDouble(); break;
        case OpCode.Dup:
        case OpCode.Pop: 
          break;
        case OpCode.Jmp: 
        case OpCode.Call:
          value = (Method)this.GetMemberFromToken(); break;
        case OpCode.Calli: 
          value = (FunctionPointer)this.reader.GetCalliSignature(this.GetInt32()); break;
        case OpCode.Ret: break;
        case OpCode.Br_S:
        case OpCode.Brfalse_S:
        case OpCode.Brtrue_S:
        case OpCode.Beq_S:
        case OpCode.Bge_S:
        case OpCode.Bgt_S:
        case OpCode.Ble_S:
        case OpCode.Blt_S:
        case OpCode.Bne_Un_S:
        case OpCode.Bge_Un_S:
        case OpCode.Bgt_Un_S:
        case OpCode.Ble_Un_S:
        case OpCode.Blt_Un_S:
          value = this.counter + 1 + this.GetSByte(); break;
        case OpCode.Br:
        case OpCode.Brfalse:
        case OpCode.Brtrue:
        case OpCode.Beq:
        case OpCode.Bge:
        case OpCode.Bgt:
        case OpCode.Ble:
        case OpCode.Blt:
        case OpCode.Bne_Un:
        case OpCode.Bge_Un:
        case OpCode.Bgt_Un:
        case OpCode.Ble_Un:
        case OpCode.Blt_Un:
          value = this.counter + 4 + this.GetInt32(); break;
        case OpCode.Switch: value = this.ParseSwitchInstruction(); break;        
        case OpCode.Ldind_I1: 
        case OpCode.Ldind_U1:
        case OpCode.Ldind_I2:
        case OpCode.Ldind_U2:
        case OpCode.Ldind_I4:
        case OpCode.Ldind_U4:
        case OpCode.Ldind_I8:
        case OpCode.Ldind_I:
        case OpCode.Ldind_R4:
        case OpCode.Ldind_R8:
        case OpCode.Ldind_Ref:
        case OpCode.Stind_Ref:
        case OpCode.Stind_I1:
        case OpCode.Stind_I2:
        case OpCode.Stind_I4:
        case OpCode.Stind_I8:
        case OpCode.Stind_R4:
        case OpCode.Stind_R8:
        case OpCode.Add:
        case OpCode.Sub:
        case OpCode.Mul:
        case OpCode.Div:
        case OpCode.Div_Un:
        case OpCode.Rem:
        case OpCode.Rem_Un:
        case OpCode.And:
        case OpCode.Or:
        case OpCode.Xor:
        case OpCode.Shl:
        case OpCode.Shr:
        case OpCode.Shr_Un:
        case OpCode.Neg:
        case OpCode.Not:
        case OpCode.Conv_I1:
        case OpCode.Conv_I2:
        case OpCode.Conv_I4:
        case OpCode.Conv_I8:
        case OpCode.Conv_R4:
        case OpCode.Conv_R8:
        case OpCode.Conv_U4:
        case OpCode.Conv_U8:
          break;
        case OpCode.Callvirt: value = (Method)this.GetMemberFromToken(); break;
        case OpCode.Cpobj:
        case OpCode.Ldobj: 
          value = (TypeNode)this.GetMemberFromToken(); break;
        case OpCode.Ldstr: value = this.GetStringFromToken(); break;          
        case OpCode.Newobj: value = (Method)this.GetMemberFromToken();break;
        case OpCode.Castclass:
        case OpCode.Isinst: 
          value = (TypeNode)this.GetMemberFromToken(); break;
        case OpCode.Conv_R_Un: break;       
        case OpCode.Unbox: value = (TypeNode)this.GetMemberFromToken(); break;
        case OpCode.Throw: break;
        case OpCode.Ldfld: 
        case OpCode.Ldflda:
        case OpCode.Stfld:
        case OpCode.Ldsfld:
        case OpCode.Ldsflda:
        case OpCode.Stsfld:
        case OpCode.Stobj:
          value = this.GetMemberFromToken(); break;
        case OpCode.Conv_Ovf_I1_Un:
        case OpCode.Conv_Ovf_I2_Un:
        case OpCode.Conv_Ovf_I4_Un:
        case OpCode.Conv_Ovf_I8_Un:
        case OpCode.Conv_Ovf_U1_Un:
        case OpCode.Conv_Ovf_U2_Un:
        case OpCode.Conv_Ovf_U4_Un:
        case OpCode.Conv_Ovf_U8_Un:
        case OpCode.Conv_Ovf_I_Un:
        case OpCode.Conv_Ovf_U_Un:
          break;
        case OpCode.Box:
        case OpCode.Newarr: value = (TypeNode)this.GetMemberFromToken(); break;
        case OpCode.Ldlen: break;
        case OpCode.Ldelema: value = (TypeNode)this.GetMemberFromToken(); break;
        case OpCode.Ldelem_I1:
        case OpCode.Ldelem_U1:
        case OpCode.Ldelem_I2:
        case OpCode.Ldelem_U2:
        case OpCode.Ldelem_I4:
        case OpCode.Ldelem_U4:
        case OpCode.Ldelem_I8:
        case OpCode.Ldelem_I:
        case OpCode.Ldelem_R4:
        case OpCode.Ldelem_R8:
        case OpCode.Ldelem_Ref: 
        case OpCode.Stelem_I:
        case OpCode.Stelem_I1:
        case OpCode.Stelem_I2:
        case OpCode.Stelem_I4:
        case OpCode.Stelem_I8:
        case OpCode.Stelem_R4:
        case OpCode.Stelem_R8:
        case OpCode.Stelem_Ref:
          break;
        case OpCode.Ldelem: 
          value = (TypeNode)this.GetMemberFromToken();
          break;
        case OpCode.Stelem: value = (TypeNode)this.GetMemberFromToken(); break;
        case OpCode.Unbox_Any: value = this.GetMemberFromToken(); break;
        case OpCode.Conv_Ovf_I1:
        case OpCode.Conv_Ovf_U1:
        case OpCode.Conv_Ovf_I2:
        case OpCode.Conv_Ovf_U2:
        case OpCode.Conv_Ovf_I4:
        case OpCode.Conv_Ovf_U4:
        case OpCode.Conv_Ovf_I8:
        case OpCode.Conv_Ovf_U8:
          break;
        case OpCode.Refanyval: value = this.GetMemberFromToken(); break;
        case OpCode.Ckfinite: break;
        case OpCode.Mkrefany: value = this.GetMemberFromToken(); break;
        case OpCode.Ldtoken: value = this.GetMemberFromToken(); break;
        case OpCode.Conv_U2:
        case OpCode.Conv_U1:
        case OpCode.Conv_I:
        case OpCode.Conv_Ovf_I:
        case OpCode.Conv_Ovf_U:
        case OpCode.Add_Ovf:
        case OpCode.Add_Ovf_Un:
        case OpCode.Mul_Ovf:
        case OpCode.Mul_Ovf_Un:
        case OpCode.Sub_Ovf:
        case OpCode.Sub_Ovf_Un:
        case OpCode.Endfinally: 
          break;
        case OpCode.Leave:   value = this.counter + 4 + this.GetInt32(); break; 
        case OpCode.Leave_S: value = this.counter + 1 + this.GetSByte(); break;
        case OpCode.Stind_I:
        case OpCode.Conv_U:
        case OpCode.Prefix7:
        case OpCode.Prefix6:
        case OpCode.Prefix5:
        case OpCode.Prefix4:
        case OpCode.Prefix3:
        case OpCode.Prefix2:
        case OpCode.Prefix1:
        case OpCode.Arglist:
        case OpCode.Ceq:
        case OpCode.Cgt:
        case OpCode.Cgt_Un:
        case OpCode.Clt:
        case OpCode.Clt_Un:
          break;
        case OpCode.Ldftn:
        case OpCode.Ldvirtftn:
          value = this.GetMemberFromToken(); break;
        case OpCode.Ldarg:
        case OpCode.Ldarga:
        case OpCode.Starg:
          value = this.Parameters(this.GetInt16()); break;
        case OpCode.Ldloc:
        case OpCode.Ldloca:
        case OpCode.Stloc:
          value = this.locals[this.GetInt16()]; break;
        case OpCode.Localloc:
        case OpCode.Endfilter:
          break;
        case OpCode.Unaligned_: value = this.GetByte(); break;
        case OpCode.Volatile_:
        case OpCode.Tail_:
          break;
        case OpCode.Initobj: value = (TypeNode)this.GetMemberFromToken(); break;
        case OpCode.Constrained_: value = this.GetMemberFromToken() as TypeNode; break;
        case OpCode.Cpblk: 
        case OpCode.Initblk:
          break;
        case OpCode.Rethrow:
          break;
        case OpCode.Sizeof: value = this.GetMemberFromToken(); break;
        case OpCode.Refanytype:
        case OpCode.Readonly_:
          break;
        default: throw new InvalidMetadataException(String.Format(CultureInfo.CurrentCulture, 
          ExceptionStrings.UnknownOpCodeEncountered, opCode.ToString("x")));
      }
      Instruction instruction = new Instruction(opCode, offset, value);
      instruction.SourceContext = this.sourceContext;
      return instruction;
    }
  }
  internal class ExpressionStack{
    internal Expression[]/*!*/ elements = new Expression[16];
    internal int top = -1;

    internal ExpressionStack() {
      //^ base();
    }

    private void Grow(){
      int n = this.elements.Length;
      Expression[] newElements = new Expression[n+64];
      for (int i = 0; i < n; i++) newElements[i] = this.elements[i];
      this.elements = newElements;
    }
    internal Expression/*!*/ Pop() {
      if (this.top < 0) return new Expression(NodeType.Pop);
      Expression e = this.elements[this.top--];
      //^ assume e != null;
      return e;
    }
    internal void Push(Expression/*!*/ e) {
      if (++this.top >= this.elements.Length) this.Grow();
      this.elements[this.top] = e;
    }
  }
  /// <summary>
  /// A thin wrapper for a synchronized System.Collections.Hashtable that inserts and strips WeakReference wrappers for the values stored in the table.
  /// </summary>
  internal class SynchronizedWeakDictionary : IDictionary{
    readonly private Hashtable/*!*/ Hashtable = System.Collections.Hashtable.Synchronized(new Hashtable());

    internal SynchronizedWeakDictionary() {
      //^ base();
    }

    public void Add(object/*!*/ key, object value){
      this.Hashtable.Add(key, new WeakReference(value));
    }
    public void Clear(){
      this.Hashtable.Clear();
    }
    public bool Contains(object/*!*/ key) {
      return this.Hashtable.Contains(key);
    }
    public IDictionaryEnumerator/*!*/ GetEnumerator() {
      return this.Hashtable.GetEnumerator();
    }
    public bool IsFixedSize{
      get{return false;}
    }
    public bool IsReadOnly{
      get{return false;}
    }
    public ICollection/*!*/ Keys {
      get{return this.Hashtable.Keys;}
    }
    public void Remove(object/*!*/ key) {
      this.Hashtable.Remove(key);
    }
    public ICollection/*!*/ Values {
      get{return new WeakValuesCollection(this.Hashtable.Values);}
    }
    public object this[object/*!*/ key] {
      get{
        WeakReference wref = (WeakReference)this.Hashtable[key];
        if (wref == null) return null;
        return wref.Target;
      }
      set{
        this.Hashtable[key] = new WeakReference(value);
      }
    }
    public void CopyTo(Array/*!*/ array, int index){
      IEnumerator enumerator = this.GetEnumerator();
      for (int i = 0; enumerator.MoveNext(); i++)
        array.SetValue(enumerator.Current, index+i);
    }
    public int Count{
      get{return this.Hashtable.Count;}
    }
    public bool IsSynchronized{
      get{return false;}
    }
    public object/*!*/ SyncRoot {
      get{return this.Hashtable.SyncRoot;}
    }
    IEnumerator/*!*/ IEnumerable.GetEnumerator(){
      return new WeakValuesEnumerator(this.Hashtable.GetEnumerator());
    }
  }
  internal class WeakValuesCollection : ICollection{
    readonly private ICollection/*!*/ collection;

    internal WeakValuesCollection(ICollection/*!*/ collection){
      this.collection = collection;
      //^ base();
    }

    public void CopyTo(Array/*!*/ array, int index){
      IEnumerator enumerator = this.GetEnumerator();
      for (int i = 0; enumerator.MoveNext(); i++)
        array.SetValue(enumerator.Current, index+i);
    }
    public int Count{
      get {return this.collection.Count;}
    }
    public bool IsSynchronized{
      get {return this.collection.IsSynchronized;}
    }
    public object/*!*/ SyncRoot {
      get {return this.collection.SyncRoot;}
    }
    public IEnumerator/*!*/ GetEnumerator(){
      return new WeakValuesEnumerator(this.collection.GetEnumerator());
    }
  }
  internal class WeakValuesEnumerator : IEnumerator{
    readonly private IEnumerator/*!*/ enumerator;

    internal WeakValuesEnumerator(IEnumerator/*!*/ enumerator){
      this.enumerator = enumerator;
      //^ base();
    }

    public object Current{
      get{
        object curr = this.enumerator.Current;
        if (curr is DictionaryEntry){
          DictionaryEntry dicEntry = (DictionaryEntry)curr;
          curr = dicEntry.Value;
        }
        WeakReference wref = curr as WeakReference;
        if (wref != null) return wref.Target;
        return null;
      }
    }
    public bool MoveNext(){
      return this.enumerator.MoveNext();
    }
    public void Reset(){
      this.enumerator.Reset();
    }
  }
#if !ROTOR && NoWriter
  [ComVisible(true), ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("7DAC8207-D3AE-4c75-9B67-92801A497D44")]
  internal interface IMetaDataImport{}
  internal class EmptyImporter : IMetaDataImport{}
#endif
#if FxCop
  class StackVariable : Local {
    internal StackVariable(TypeNode type, string name)
      : base(type) {
      this.NodeType = NodeType.StackVariable;
      this.Name = Identifier.For(name);
    }
    internal StackVariable(TypeNode type, int index)
      : base(type) {
      this.NodeType = NodeType.StackVariable;
      this.Name = Identifier.For("stack$" + index.ToString(CultureInfo.InvariantCulture));
    }
  }
#endif
}